CSS selector 우선순위 (specificity)

요소 선택자(Element Selector) 점수 계산하기

CSS에서는 요소의 선택자에 따라 우선순위가 나뉜다.

우선순위 가중치를 통해 스타일을 적용할 순서를 결정하지만 현재는 가중치 계산 방식이 브라우저별로 다르기 때문에 선택자의 상대 우선순위를 알아두는 것이 더 좋다.

예를 들어 기존에는 가중치가 class:10, id:100으로, class 10개가 1개의 id와 동등한 가중치를 가졌지만 현재는 가중치가 달라져 일부 브라우저에서는 256개의 class가 1개의 id와 동등한 우선 순위를 가진다. (참고:stackoverflow)

선택자는 다음과 같은 우선순위를 가진다.

!important > inline style > id > class (pseud0) > element (pseudo)

따라서 선택자별로 상대적인 가중치를 판단하여 높은 순서에 따라 왼쪽부터 comma로 구분하여 계산하는 것이 좋다.

높음inline style , id , class (pseud0) , element (pseudo) <낮음
Ex1) 0 , 1 , 2 , 1
Ex2) 0 , 0 , 200 , 10
? Ex1이 Ex2보다 가중치가 높음

예를 들어 다음과 같이 id, class 선택자가 모두 사용되는 경우 우선순위에 따라id 스타일이 적용된다.

.myMenuClass{
  color:green;
}

#myMenuId{
  color:red;
}

<h1 id="myMenuId" class="myMenuClass">This is it</h1>

그리고 가중치의 합산은 다음과 같다.

#myMenuId{
  color:red;
}

.myMenuClass{
  color:blue;  
}

h1#myMenuId{
  color:orange;  
}

<h1 id="myMenuId" class="myMenuClass">This is it!</h1>

우선 순위를 계산해보면,

#myMenuId : 0,1,0,0 / .myMenuClass : 0,0,1,0 / h1#myMenuId : 0,1,0,1

따라서 마지막 orange color가 적용된다.

!important는 모든 가중치를 무시하고 최우선적으로 적용하는 치트키와 같다. !important가 요소에 중복되는 경우 가장 뒤에 선언된 !important가 적용된다.

하지만 !important의 사용&남용은 평화로운 생태계를 위협하는 존재가 될 수 있으므로 최대한 사용하지 않는 것이 정신 건강과 코드 구성에도 좋다.

맥에서 localhost 접속 시 dns_probe_finished_nxdomain 에러 처리

맥(Mac)에서 사용자 지정 localhost 호스트 도메인 수정하기

localhost를 기본 설정으로 사용하면 문제없이 로컬 서버에 접속이 가능하지만 local.page.com 등과 같이 임의로 주소를 설정하게 되면 위와 같이 사이트에 연결할 수 없다는 DNS 에러가 발생합니다.

기본적으로 localhost의 주소는 127.0.0.1으로 설정되어 있으므로 localhost를 주소로 사용하면 문제없지만 localhost의 주소명이 바뀐다면 별도의 설정을 통해 알려주어야 합니다.

맥에서 설정 파일은 다음 위치에 있습니다.

/private/etc/hosts

이 파일을 vi 에디터를 통해 설정해보겠습니다(관리자 권한 필요).

% sudo vi /private/etc/hosts

명령어를 실행하고 패스워드를 입력하면 다음과 같은 화면이 나옵니다.

여기에 임의의 주소명과 이 주소명이 찾아갈 IP를 넣어주면 됩니다.

i 키를 누르면 편집이가능하며 앞에는 host 주소 127.0.0.1, 뒤에는 사용할 임의의 주소명을 넣어보겠습니다.

입력 후 저장을 위해 ESC를 누른 뒤 :를 입력, 다시 콘솔에 qw! 를 입력하고 엔터를 치면 저장이 완료됩니다.

완료 후 로컬 서버를 실행하고 local.page.com에 접속하면 문제없이 접속되는 것을 확인할 수 있습니다.

rgba를 사용해 opacity의 상속 문제 해결(투명도 조절)

자식 노드에 상속되는 opacity와 단독적인 rgba

부모 노드에 opacity 효과를 주면 자식 노드에도 상속되어 투명 효과가 함께 적용됩니다.

자동으로 상속이 되므로 다음과 같이 표시됩니다.

아래 설정으로 색상을 지정한 결과입니다.
배경 black
opacity:0.5
background:yellow
background:red

보다시피 yellow, red에 opacity가 적용되어 색상이 흐려진 것을 볼 수 있습니다.

그렇다면 이 상속 문제를 해결하기 위해서는 어떻게 해야 할까요?

간단하게 opacity 대신 rgba를 사용하면 됩니다.

투명도를 포함하는 색상의 지정은 다음과 같습니다.

rgba(R, G, B, opacity);

다음과 같이 사용할 수 있습니다.

위 박스에 해당하는 색상인 #9ADFFD을 rgba 방식으로 표현해보겠습니다.

16진수를 10진수로 변형한 값인 9A=154, DF=223, Fd=253을 각각 R, G, B 위치에 넣어주고 마지막 인수는 0~1 사이의 값을 넣어주면 됩니다.

background : rgba(154, 223, 253, 0.5);

이제 자식 노드는 opacity가 적용되지 않으므로 색상이 선명해진 것을 확인할 수 있습니다.

검은 배경을 사용해도 자식 노드에 선명도가 살아난 것을 확인할 수 있으며 이를 통해 상속되지 않는다는 것을 알 수 있습니다.

테스트에 사용한 코드는 다음과 같습니다.

<div class="div0">
    <div class="div1">
      modify
    </div>
    <div class="div2">
      delete
    </div>
</div>

.div0{
  height:100px;
  background : rgba(0, 0, 0, 0.5);
  display:flex;
  justify-content:center;
  align-items:center;
}

.div1{
  width:200px;
  height:50px;
  background-color:gold;
  display:flex;
  justify-content:center;
  align-items:center;
  color:white;
}

.div2{
  width:200px;
  height:50px;
  background-color:red;
  display:flex;
  justify-content:center;
  align-items:center;
  color:white;
}

웹스톰(Webstorm)에서 prettier 활성화하기

웹스톰에서 prettier를 설정하는 방법

웹스톰(webstorm)에는 기본적으로 prettier가 설치되어 있습니다.

그러므로 npm 또는 yarn을 통해서 node_modules에 prettier를 설치해주고 prettier관련 설정만 해주면 됩니다.

npm install --save-dev --save-exact prettier

위와 같이 설치해준 뒤 File -> Settings -> Languages & Frameworks -> JavaScript -> Prettier에 들어가서 다음과 같이 설정해줍니다.

Prettier package에는 node_modules/prettier가 위치하는 주소를 지정하고 아래 체크 박스를 모두 체크해주면 저장 시에도 prettier가 작동이 됩니다.

작동이 안될 때는 웹스톰을 재시작.

prettier 작업의 단축키는 alt+ctrl+shift+p 입니다.

개발자의 일본어 사전(開発の辞書)

開発者がよく使う単語コレクション

일본어 서적을 번역하면서 정리하는 개발 용어.

영어 단어를 그대로 쓰는 카타카나가 많지만 장음이나 표기법 등의 참고를 위해 함께 정리.



上書き [うわがき] – 덮어쓰기(overwrite)
受け取る [うけとる] – 받다(receive)
アクセス [あくせす] – 액세스(access)
値 [あたい] – 값(value)



コンポーネント [こんぽーねんと] – 컴포넌트(component)
コールバック [こーるバック] – 콜백(callback)
切り替え [きりかえ] – 전환(convert)
環境 [かんきょう] – 환경(environment)
組み合わせ [くみあわせ] – 조합(combination)
関数 [かんすう] – 함수(function)



実装 [じっそう] – 마운트(mount)
疎結合 [そけつごう] – 소결합(loose coupling)
設計 [せっけい] – 설계(design)
スキル [すきる] – 스킬(skill)
座標 [ざひょう] – 좌표(coordinate)



トリガー [とりがー] – 트리거(trigger)
デプロイ [でぷろい] – 배포(deploy)
ツール [つーる] – 툴(tool)
データ [でーた] – 데이터(data)
テキスト [てきすと] – 텍스트(text)



認証 [にんしょう] – 인증(identification)



振る舞い [ふるまい] – 동작(behavior)
ヘッダー [へっだー] – 헤더(header)
ボディ [ぼでぃ] – 바디(body)
引数 [ひきすう] – 인수(argument), 함수 호출 시 전달 값
パラメータ [ぱらめーた] – 파라미터(parameter), 함수 정의 시 전달 값
フロントエンド [ふろんとえんど] – 프론트엔드(frontend)
フロー [ふろー] – 흐름, 플로우(flow)



マイグレーション [まいぐれーしょん] – 마이그레이션(migration)



やりとり – 주고 받음
呼び出す [よびだす] – 호출(call)



ルーティング [るーてぃんぐ] – 라우팅(routing)
レンダリング [れんだりんぐ] – 렌더링(rendering)


interface, type 차이점이 뭘까(Typescript)

비슷하지만 동일하지 않은 interface vs type

타입스크립트에서 타입을 선언하기 위해서는 interface 또는 type 키워드를 사용합니다.

각각의 선언 방식은 다음과 같으며 =의 유무만 다릅니다.

// interface
interface Team{
  name : string
}

// type
type Team = {
  name : string
}

그리고 타입의 확장 방법은 다음과 같습니다.

// interface
interface City extends Team {
  city : string
}

// type
type City = Team & {
  city : string
}

interface와 type의 가장 큰 차이점은 바로 선언적 확장(Declaration Merging) 기능인데요.

선언적 확장이란 이미 선언된 타입 선언에 필드를 추가하는 것입니다.

하나는 가능하고 하나는 가능하지 않은데 interface만 가능한 것이 특징입니다.

사용 방법은 다음과 같습니다.

interface Team {
  name : string
}

interface Team {
  manager : string
}

위와 같은 방법으로 이미 선언된 interface에 다시 필드를 선언할 수 있습니다.

하지만 type을 다음과 같은 방법으로 사용하면 에러가 발생합니다.

type Team = {
  name : string
}


// Error 발생 -> 'Duplicate identifier 'Team'
type Team = {
  manager : string
}

추가로 type은 원시형(number, string 등) 데이터를 다른 이름으로 지정해서 사용할 수 있지만 interface는 불가능합니다.

자세한 내용은 다음 코드와 같습니다.

//type으로 원시형 데이터의 이름을 지정
type NameDataType = string;

const printName = (name : NameDataType ) => {
  console.log(name);
}

//interface는 불가
interface NameType extends string {
}

차이점을 신경써도 되지 않을 상황이라면 취향에 따라 선택하면 되지만 기본적으로는 interface를 쓰면 큰 문제가 없다고 합니다.

참고 : typescript 공식 문서

Emotion(Styled), Props 전달하기(Typescript)

Typescript와 함께 동적 CSS 스타일 사용하기
import styled from "@emotion/styled";

const StyledPropsTest = styled.div`
  width: 120px;
  height: 40px;
  font-size: 25px;
  background: ${(props) => (props.testProps ? "blue" : "red")};
  color: white;
`;

const StyledTest = ({testprops}) => {
  return(
    <StyledPropsTest testProps={testprops}>Prop Test</StyledPropsTest>
  )
}

export default StyledTest;

컴포넌트 내부에서 사용하는 변수를 CSS에 전달하여 동적 스타일을 적용하기 위해서는 위와 같이 props를 전달하는 방법이 있습니다.

하지만 Typescipt를 사용하여 custom props를 사용하면 다음과 같은 에러를 만나게 됩니다.

(property) testProps: boolean
Type ‘{ children: string; testProps: boolean; }’ is not assignable to type ‘IntrinsicAttributes & { theme?: Theme | undefined; as?: ElementType<any> | undefined; } & ClassAttributes<HTMLDivElement> & HTMLAttributes<…>’.
Property ‘testProps’ does not exist on type ‘IntrinsicAttributes & { theme?: Theme | undefined; as?: ElementType<any> | undefined; } & ClassAttributes<HTMLDivElement> & HTMLAttributes<…>’.ts(2322)

이는 타입스크립트에서 props의 타입을 체크하기 때문인데요.

다음과 같이 간단하게 <{data:type}>의 타입 단언(Type Assertion)으로 해결할 수 있습니다.

const StyledPropsTest = styled.div<{testProps:boolean}>`
  width: 120px;
  height: 40px;
  font-size: 25px;
  background: ${(props) => (props.testProps ? "blue" : "red")};
  color: white;
`;

다음과 같이 에러가 사라진 것을 확인할 수 있습니다.

leaflet, 반복되는 지도에 marker 표시하기(react)

맵 축소 시 반복되는 지도에 Marker 반영하기

다른 옵션을 설정하지 않는 한 맵을 최대로 축소하면 다음과 같이 지도가 반복되어 나타납니다.

여기서 맵을 오른쪽이나 왼쪽으로 넘겨서 중심을 바꿔도 Marker는 그대로 있습니다.

하지만 맵 렌더링 시 다음과 같이 ‘worldCopyJump’ 옵션을 넣어주면 중심이 이동하더라도 기존의 Marker를 모두 표시할 수 있습니다.

<MapContainer
   center={[35.102, 129.067]}
   zoom={5}
   scrollWheelZoom={true}
   worldCopyJump
>

옵션 하나만으로 맵을 이동하면 Marker도 이동하여 같은 좌표에 표시되는 것을 확인할 수 있습니다.

leaflet 맵 표시 언어 변경

지도 데이터 서버 변경하기

leaflet의 기본 맵은 각 지역마다 현지 나라의 언어로 표기되어 한국 맵은 한국어, 일본 맵은 일본어, 프랑스 맵은 프랑스어로 표기되어 있습니다.

하지만 전체 맵을 영어로 표기하고 싶거나 산맥, 해양 등 용도에 맞게 지도의 이미지를 변경하고 싶을 때는 아래 링크에서 원하는 맵의 유형과 서버를 확인하여 서버만 변경해주면 됩니다.

1. 링크에서 서버 확인

http://leaflet-extras.github.io/leaflet-providers/preview/

링크에 접속하면 다음과 같은 화면입니다.

초록색 네모칸에서 서버 정보, 빨간색 네모칸에서 맵의 종류 샘플을 볼 수 있습니다.

샘플로 OpenStreetMap.France를 적용해보도록 하겠습니다.

빨간 네모칸에서 OpenStreetMap.France을 선택하면 초록 네모칸에 서버 정보가 표시됩니다.

‘https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png’

‘&copy; OpenStreetMap France | &copy; <a href=”https://www.openstreetmap.org/copyright”>OpenStreetMap</a> contributors’

이 두 부분만 코드에서 변경해주면 바로 적용이 됩니다.

2. 코드 적용

import { MapContainer, TileLayer, useMap, Marker, Popup } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import { icon } from "leaflet";
const Icon = icon({
  iconUrl: "marker-icon.png",
  iconSize: [16, 16],
  iconAnchor: [12, 16],
});

const MyMap = () => {
  return (
    <MapContainer
      center={[37.56675, 126.97842]}
      zoom={10}
      scrollWheelZoom={true}
      style={{ width: "500px", height: "500px" }}
    >
      <TileLayer
        attribution='&copy; OpenStreetMap France | &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png"
      />
      <Marker position={[37.56675, 126.97842]} icon={Icon}>
        <Popup>서울시청이에요.</Popup>
      </Marker>
    </MapContainer>
  );
};

export default MyMap;

설정에 따라 변경된 맵과 언어를 확인할 수 있습니다.

CSS, calc()를 사용해 main(body) 높이 자동 설정하기

CSS에서 calc 메서드 사용하기

CSS에서 calc() 메서드를 사용하면 window 창의 사이즈 변경에 따라 자동으로 길이를 계산할 수 있습니다.

header, main, footer의 레이아웃을 나눌 때 main에서 calc()를 사용하게 되면 윈도우 창의 크기가 줄어들어도 main의 내용이 잘릴 염려 없이 가변적으로 창의 크기에 맞게 표현할 수 있습니다.

1. 필요성

예를 들면 다음과 같은 상황에서 유용합니다.

위와 같은 화면이 있을 때 윈도우 창의 사이즈를 줄이면(resizing) 가운데 main의 스크롤을 끝까지 내려도 데이터가 모두 표시되지 않을 때가 있습니다.

스크롤을 끝까지 내렸지만 이렇게 r 까지만 표시되고 아랫부분은 짤려서 표시되지 않습니다.

이런 상황에서 main의 div 높이를 계산하여 자동으로 조절해주면 다음과 같이 윈도우가 리사이징 되더라도 화면이 짤리지 않고 유지되는 것을 볼 수 있습니다.

2. 적용하기

main div의 높이(height)에 calc() 메서드를 사용하여 ‘뷰 높이(vh) – 나머지 공간’을 해주면 됩니다.

다만 전달값의 +, – 앞 뒤에는 반드시 공백을 삽입해야 합니다.

// OK
height: calc(100vh - 300px);

// 에러(공백 없음)
height: calc(100vh-300px);

결과는 다음과 같습니다.