크고 장기적인 프로적트에 많은 개발자가 함께 참여할 경우 많은 규칙들을 세우듯, css 또한 아래와 같은 목적들을 위해 일괄적으로 규범을 정해 놓고 진행 하는 것이 좋습니다~
- 스타일시트를 멘테난스 가능하도록 늘 정비한다.
- 코드는 늘 읽기 쉬운 상태로 유지한다.
- 스타일시트를 언제나 확장 가능한 상태로 유지한다
이러한 목적달성을 위해 지켜야할 몇가지 기술적인 기법들이 몇가지 있습니다.
이 문서는 우선 초반부엔 문법과 포멧, css의 구성에 대해서 기술하고 있고 후반부에는 css를 작성하거나 설계하기에 앞서 생각하는 방법과 구성하는 법에 대해서 알아보겠습니다. 어떤가요? 재미있을것 같죠?ㅋㅋ
- CSS파일의구성
- 소스파일의순서
- 룰셋구성
- 명명법칙
- 코멘트
- CSS작성법의이론
- [새로운컨포넌트의 작성방법](#새로운컨포넌트의 작성방법)
- 오브젝트지향CSS
- 레이아웃
- [UI사이즈 지정](#UI사이즈 지정)
- 생략기법
- ID에대해서
- 셀렉터
- CSS셀렉터의의도
!important
- 매직넘버와절대값
- 조건이붙는스타일시트
- 디버그
- 프리프로세서
예를 들어 제대로된 문서가 있다고 해도 우리들은 그저 기존 공통 포멧에 맞춰 최선을 다해 계속 따라 이어나갈 뿐입니다. 그것은 코멘트의 일관성과 문법의 일관성 그리고 라벨을 붙이는 것에 대해 일관성이 있음을 의미하지요.
스타일시트의 파일에 대해 가능한 가로 80문자가 넘지 않도록 제한을 둡시다. 예외적으로는 그라데이션 지정을 하는 문법 혹은 코멘트 내의 URL등이 있습니다만 이것은 어쩔수 없는 것이므로 그대로 사용하여도 무관합니다.
저는 「태그문자」보다 4스페이스가 들어간 인덴트가 좋기도 하고 멀티라인CSS(CSS의 지정을 복수행으로 나누는 방법)를 사용해서 작성하기도 합니다.
CSS를 한 개의 큰 파일에 정리하는 걸 좋아하는 분들이 있습니다. 이제부터 배울 가이드라인에 따르는 한 특별히 문제는 없습니다. 저는 Sass로 갈아탔기 때문에, 스타일시트 파일을 작게 나눠 인클루드 시키도록 사용하고 있습니다. 어느쪽이든 상관은 좋습니다. 어느쪽을 하시더라도 이제부터 설명할 룰과 가이드라인에 적용가능합니다. 한 가지 큰 차이로 치자면 목차와 섹션 타이블을 붙이는 방법뿐입니다. 아래의 설명을 읽어 주세요.
스타일시트를 작성하기 전에 우선 스타일시트 내용에 목차를 적어둡시다. 예를들어 아래와 같습니다.
/*------------------------------------*\
$CONTENTS
\*------------------------------------*/
/**
* CONTENTS............지금 여기
* RESET...............디폴트설정
* FONT-FACE...........브랜드 폰트의 설정
*/
목차가 있으면, 이 파일이 어떤 역활과 기능을 하는지 다른 개발자가 척 봐도 딱 알수 있습니다. 목차의 각항목은, 각 섹션의 타이틀에 대한 설명입니다.
혹시 하나의 거대한 스타일시트에서 작업을 하고 계시다면, 목차에 적힌 모든 섹션 내용은 모두 같은 파일 안에 정리되어 있겠죠. 또는 당신이 여러개의 css파일에서 작업을 하고 있다면 , 목차의 각 항목은 인클르드 되어있는 각가의 파일 안에 있을것입니다.
목차에 대응할 섹션타이틀이 없다면 이건 뭐 목차를 만들어도 아무런 도움도 되지 않습니다 섹션은 아래와 같이 적어주세요.
/*------------------------------------*\
$RESET
\*------------------------------------*/
$
기호를 섹션명 시작전에 작성하면、$[섹션명]
과 같이 검색해서 한 번에 섹션타이틀만을 검색대상으로 지정 할수가 있습니다.
혹 하나의 스타일시트에서 작업을 하고 있다면 섹션의 중간에 빈행을 5개 집어넣어주세요.
아래와 같습니다.
/------------------------------------
$RESET
*------------------------------------*/
[여기에
리셋
스타일을 적습니다]
/*------------------------------------*\
$FONT-FACE
\*------------------------------------*/
이 빈행에 감싸여 있다면 엄청 긴 소스가 적힌 파일 안에서 스트롤을 하더라도 바로 섹션 구분이 될겁니다. 혹시 당신이 여러개의 스타일시트에서 작업을 하고 있는 경우라면 각 파일의 머리말에 섹션타이틀을 적는 걸로도 충분할 겁니다. 빈행은 넣을 필요가 없겠죠.
스타일시트의 디테일도가 낮은 순으로 적어줍시다. 옳바른 순으로 적는 것만으로도 상속과 캐스태이딩의 이점을 충분을 살릴 수 있습니다. 더불어 캐스캐이드는 css의 첫글자 C입니다.
대부분의 경우 구성이 잘된 스타일시트의 순서는 아래와 같이 되어 있습니다.
- 리셋 – 준비지점.
- 엘리먼트(요소) – 클래스명 없음
h1
이나ul
등. - 오브젝트、추상화 — 범용적、전체적인 디자인 패턴.
- 컴포넌트 – 오브젝트로 구성된 부분(컴포넌트)이나 그 확장.
- 임시 스타일 – 에러상태..등등
이것들의 자세한 설명은 이어서 계속하겠습니다. 여기서 중요한 점은 각 섹션은 전에 정의한 내용을 기준으로 계승하여 구성되어 있습니다. 스타일이 무너지는 일은 되도록이면 피하고 클래스의 재사용성을 높여 여러 문제에 대응할 수 있도록 스타일시트를 설계합시다.
좀더 자세한 내용을 보고 싶으신 분은、Jonathan Snook의 SMACSS 을 강추합니다.
[selector]{
[property]:[value];
[<- Declaration ->]
}
저는 룰셋구성을 세울 때 몇가지 표준적인 방법을 사용하고 있습니다.
- 클래스명의 단어는 하이픈으로 구분하고(단、BEM기법에 대해서는 제한적이지 않습니다.。※BEM)
- 스페이스 4개의 인덴트
- 멀티라인
- 적절한 선언순서(알파벳순서아님)
- 벤더prefix로 정리된 인덴트
- DOM구성과 일치하도록 룰셋을 인덴트
- 세미콜론은 반드시 붙입니다.
아래가 예입니다.
.widget{
padding:10px;
border:1px solid #BADA55;
background-color:#C0FFEE;
-webkit-border-radius:4px;
-moz-border-radius:4px;
border-radius:4px;
}
.widget-heading{
font-size:1.5rem;
line-height:1;
font-weight:bold;
color:#BADA55;
margin-right:-10px;
margin-left: -10px;
padding:0.25em;
}
여기에、 .widget-heading
가 .widget
의 자식요소라는 걸 알게하기 위해선、.widget-heading
의 룰셋를 .widget
보다도 더 깊게 인덴트 해주어야 합니다.
이것은 개발자가 룰셋의 인덴트를 살짝 훑어보는 것만으로 룰셋 사이의 관계를 쉽게 알게 하는데 편리합니다.
.widget-heading
의 각 css선언이 순서대로 나열되어 있다는걸 쉽게 알수 있습니다.
이런 경우、.widget-heading
는 텍스트가 메인의 요소이기 때문에 우선 텍스트를 수식하는 내용부터 시작해서 그밖의 나머지 요소를 나열하면 됩니다.
멀티라인의 룰 예외는 아래와 같은 것들 입니다.
.t10 { width:10% }
.t20 { width:20% }
.t25 { width:25% } /* 1/4 */
.t30 { width:30% }
.t33 { width:33.333% } /* 1/3 */
.t40 { width:40% }
.t50 { width:50% } /* 1/2 */
.t60 { width:60% }
.t66 { width:66.666% } /* 2/3 */
.t70 { width:70% }
.t75 { width:75% } /* 3/4*/
.t80 { width:80% }
.t90 { width:90% }
이 예의 경우([inuit.css’s table grid system] (https://github.com/csswizardry/inuit.css/blob/master/base/_tables.scss#L96) 에서 인용)、이처럼 일행으로 정리해버리는게 좀더 알기 쉽습니다.
대개 저는 클래스명의 단어를 하이픈으로 구별하고 있습니다만(예:.foo-bar
、나쁜예:.foo_bar
, .fooBar
)
대부분의 경우에 대해서는 저는 BEM기법을 사용하고 있습니다.(BEM이란、Block、Element、Modifier의약어입니다)
BEM
는 일종의 명명법입니다. 이 방법을 사용하는 걸로 ,CSS셀렉터를 보다 엄격하게 하여 한눈에도 알아보기 쉽고 의미 있는 코드를 만들 수 있습니다.
이 명명법칙의 패턴은 아래와 같습니다. .block{} .block__element{} .block--modifier{}
.block
는 상위레벨의 추상명이나 컨포넌트명을 표시합니다..block__element
는.block
의 요소를 전체적으로 보조하는 자식요소를 표시합니다.block--modifier
는.block
요소자체에 있는 상태나 별개의 버전을 표시합니다.
BEM클래스명과 어떻게 사용할지 혹은 하나의 참고예 를 표시합니다.
.person{}
.person--woman{}
.person__hand{}
.person__hand--left{}
.person__hand--right{}
이 예에서는 우선 person(사람)을 나타내는 기본적인 오브젝트(추상적인 개념)을 정의하고 있습니다. 이 person에는 woman(여성)이라는 별도의 타입이 있습니다. 게다가 person은 hand(손) 요소를 자식요소로써 가지고 있으며 hand 요소에는 left(좌)와 right(우)라는 두 부류가 있다는 걸 알수 있습니다.
이 명명법칙에 있어서 셀렉터는 기본적인 오브젝트별로 명칭공간을 나누는게 가능합니다.
게다가 자식요소인지(__
) 그 아래 부류인지를(--
) 용도에 구분함에 따라 이 셀렉터가 어떤 역할을 가지고있는지 알 수 있습니다.
.page-wrapper
라는 독립적인 셀렉터명을 가지고 생각해봅시다.
이 셀렉터는 명칭은 추상요소나 컨포넌트의 일부가아니라 page wrapper(페이지를 감싸는)라는 명칭으로 지은것이므로 이것은 바른 작명이라고 볼 수 있는겁니다.
그러면 .widget-heading
을 살펴봅시다. 요건 어떤 컨포넌트와 관계하고 있을것이므로(.widget
의 자식요소라고 생각됩니다) 이럴경우엔 .widget__heading
라고 이름을 바꾸는게 적절하겠네요.
BEM법은 쫌 보기좋지도 않고 쓸데없이 장황한 감이 있지만 클래스명만을 보고 요소간의 관계나 기능을 아는게 가능하므로 대단히 유용합니다. 또한 BEM기법은 반복적인 단어가 빈번하므로 gzip같은 전형적인 압축형식과도 잘 어울립니다.
당신이BEM법칙을 사용하든 하지 않든 클래스명은 언제나 잘 생각해서 명명해야 합니다.
구체적인 이하와 같습니다만,,너무 짧지않게 너무 길지 않게 필요한만큼 최대한 짧은 길이로 해주세요.
이어서 오브젝트와 추상명은 막연하게 느끼게 하지요(예를들어 .ui-list
라든지 .media
)
될수 있는 한 광범위하게 재사용할수 있게 두고 구체적으로 오브젝트를 확장할 때 확실한 명칭을 붙여 (예를 들어 .user-avatar-link
등등)둡니다
클래스 명의 숫자나 그에따른 파일사이즈의 증가에 대해 신경쓸 필요는 없습니다. gzip압축이 믿을 수 없을 만틈 작게 압축해주기 때문이지요.
별 대단한건 아니지만 HTML내에서 클래스명을 읽기 쉽기 하기 위해 간격을 2스페이스 떨어뜨려놔주세요. 아래와 같습니다.
이런 스페이스를 자주 사용하는 것으로 인해 복수의 클래스명을 좀더 쉽게 파악할 수도 있고 읽기 편하게 됩니다.
CSS스타일에서 사용중인 클래스명을 JavaScript에서 사용하는 건 절대로 하지 맙니다!!!! JS로 스타일 클래스명을 사용하게 되면 자못 예상치도 못한 JS동작이 움직이지 않게 되는 엄청난 일이 벌어질 수도 있습니다.
혹시라도JS에서 사용하고 싶은 클래스명을 마크업할 필요가 있다면 JS용이라고 알수 있게 클래스명을 붙여둡시다.
단순하게 .js-
라는 식으로 붙이는 방법도 있습니다. 예를들어 .js-toggle
라던지 .js-drag-and-drop
이겠네요.
이런 경우 JS용과 CSS용의 클래스명을 동시에 마크업하셔도 상관없습니다. 중복 기재라 귀찮다거나 하진 않을거예요.(바로 옆에 붙이는 거니깐요~)
<th class="is-sortable js-is-sortable">
</th>
위의 마크업을 예로들어 2개의 클래스를 병행기재하고 있는데요 한 개는 Sort가능한 테이블 컬럼에 설정한 스타일명 다른 하나는 Sort기능 스크립트용 클래스명입니다.
영국인 개발자(color가 아니라 colour라고 써버리며 시간을 낭비하는 사람)도 있는듯 하지만 저는 일관성을 중시해서 미국영어로(US-English) CSS를 쓰는게 옳다고 생각하고 있습니다.
다른 엉어 코드와 마찬가지로 CSSS를 color:red;
처럼 미국영어로 쓰면서 .colour-picker{}
같이 (영국영어)클래스명을 섰어 쓰는건 일반적이진 않습니다.
이전엔 아래와 같이 2개 국어로 클래스명을 작성하는 법을 어드바이스한적도 있었습니다.
.color-picker,
.colour-picker{
}
그러나 최근에 와서 저는 매우 거대한 Sass를 사용한 프로젝트에서 대량의 「colour」를 사용한 변수 (예를들어 $brand-color
또는 $highlight-color
)를 유지보수 하는 동안 이건 정말 큰일나겠구나 하고 깨달았습니다. 이것저것 2번 정도 검색하거나 변경하거나 해야하기 때문이었죠.
일관성이 중요한 경우엔 언제나 클래스명과 변수는 Locale Categories에 맞춰 적도록 합시다.
저는 docBlock풍의 코멘트 스타일을 폭 80문자에 제한하여 사용하고 있습니다. 아래와 같습니다.
/**
* 이건docBlock풍 코멘트 입니다.
*
* 여기는 매우 긴 코멘트로 상세하고 내용이 긴글이 옵니다.
* 좀 길긴하지만 폭 80문자로 제한을 둬서 반복사용합니다.
*
* 코멘트의안에 마크업을 써두는 경우 아래와 같이 써 주세요.
*
<div class=foo>
<p>Lorem</p>
</div>
*
* 코드를 써야할 경우엔 복사 붙여넣기의 방해가 되지 않도록 아스테릭스
* 로 행을 시작하지 말아주세요.
*/
여러분 코멘트와 정리문서는 될수 있는한 많이 작성해주세요. 당신에게 있어선 코멘트가 없어도 코드가 잘 보이고 충분하다고 생각할 수 있겠지만 다른 개발자에게 있어선 절대 그럴리 없을지 모르니까요. 한개 분량의 작은 코드를 작성 했어도 그때도 역시 코멘트를 꼭 적어주세요.
여기서는 아래의 세가지 코멘트를 사용한 몇개의 진취적인 기술을 소개합니다.
- 준제한 셀렉터
- 코드에 태그붙이기
- 상호링크포인터
셀렉터를 제한적으로 사용해야 하는건 딱히 아닙니다. 그러니까 ul.nav{}
처럼 써야하는건 아니라는 거죠
단순하게 .nav
라고 쓰면됩니다. 셀렉터를 제한적으로 사용하는건 셀렉터의 퍼포먼스를 저하시키는 일입니다.
또한 제한한 요소 이외에 적용이 되지 않음으로 클래스명의 자사용빈도도 당연히 떨어지게 되겠죠.
전혀 너베~네버 좋은 일이 아니기 때문에 어쨋든 될수 있는대로 피하도록 합시다.
게다가 바로 옆 개발자의 클래스의 의도를 전달할때에 가끔 편리할 때가 있습니다.
예를 들어 .product-page
라는 클래스명에 대해 생각해 볼까요. 이 클래스명은 상위에 오는 뭔가가 있을법한 느낌이 드네요(위에서 배웠죠? 명칭방법)어쩌면 html
나 body
요소에 사용할지도 모르겠네요.
그래도 역시 .product-page
라는 명칭만으로는 대체 어떤 요소에 사용해야할지 도무지 모르겠어요.
그러면 코멘트를 사용해서 제한적인 셀렉트처럼 보이게끔 해볼가요. 우선 이 클래스를 어떤 요소에 사용해 주었으면 좋을지 다른 개발자에게 가르쳐주는게 가능합니다. 아래처럼 말이예요.
/*html*/.product-page{}
이걸로 이 클래스명을 어떤 요소에 사용하면 좋을지를 정확하게 알게 되었을 겁니다. 게다가 좀전에 설명한 상세화나 재사용성에 대한 문제도 없을겁니다.
다른 예를 들어볼게요.
/*ol*/.breadcrumb{}
/*p*/.intro{}
/*ul*/.image-thumbs{}
이처럼 이 클래스를 어디에 사용할지 셀렉터의 동작을 바꾸지 않고 알려주는 것도 가능합니다.
혹시 당신이 새로운 컨포넌트를 작성한다고 치고 몇개의 태그에 코멘트를 적고나서 그 컨포넌트가 가진「기능」에 대해 관계성을 부여해봅시다. 예를들어 아래와 같습니다.
/**
* ^navigation ^lists
*/
.nav{}
/**
* ^grids ^lists ^tables
*/
.matrix{}
이렇게 태그에 코멘트를 붙이는 법은 다른 개발자가 「기능」라고 검색할 경우 자신이 찾던 코드에 쉽게 도달하는게 가능해집니다.
결국 개발자가 리스트한 기능에 대해 무언가 검색할 경우 ^lists
라는 단어를 검색한다고 치고.nav
나 .matrix
라는 클래스명을(검색결과가 어마어마하게 나올지도 모르겠네요)정확하게 발견하는게 가능해진다는 말입니다.
오브젝트지향인 방법의 개발을 진행하고 있으면 뼈대가 되는 기본적인 틀의 CSS와 그에 대응하는 피부(보여지는 부분) 역할의 확장부분으로 나눠 작업하는 경우가 많다고 생각되네요. 이런 경우 기본부분과 확장부분은 밀접한 관계가 있습니다만 파일상으로는 떨어져 존재하는 경우가 많지요. 이 기본부분과 확장부분에 서로를 잘 알수 있는 링크를 붙이기 위해 상호링크포인터를 사용하면 좋습니다. 이걸 하기 위해서는 아래와 같은 코멘트를 문서에 적어주세요.
우선 기본부분은 이렇게 써주세요.
/**
* `.foo` 을 theme.css로부터 계승함
*/
.foo{}
다음으로、피부 부분의 확장부분을 이렇게 적어주세요.
/**
* base.css 의 `.foo` 을 계승하고 있음.
*/
.bar{}
이걸로 떨어졌던 지점의 코드에 강한 관계 형성이 되었습니다.
지금까지의 셀렉터는 어떤식으로 CSS를 구성하고 기술할것인지에 대해 다루었습니다. 몹시 형식적인 내용이었지요. 이 섹션에서는 좀더 이론적인 생각들과 구성법들에 대해 설명하겠습니다.\
새로운 컨포넌트(부품)을 만들 경우는 우선 CSS보다도 마크업 부터 작성해봅시다. 이방법을 이용함에 따라 어느 CSS속성이 계승되어지고 무엇을 추가해야할지를 시작적으로 확인 할수 있고 이로인해 장황하게 길게 쓰는 CSS의 잘못된 사용을 피할 수 있습니다. 마크업을 먼저 작성하는 걸로 표시되는 데이터나 내용 또는 그것이 가진의미에 대하 집중할 수가 있습니다. 그렇게 하면 이후에 적절한 클래스명과 CSS의 사용에 대해 생각하고 쓰는게 가능해지는 겁니다.
저는 오브젝트지향 CSS방식으로 작업하고 있습니다. 컴포넌트의 틀이 아닌 기본적인 부분과 확장가능한 부분(피부역할)으로 나눠서 쓰고 있는거죠. 실제사용된 소스는 아닙니다만 예를들자면 이런 분위기입니다 .room{}
.room--kitchen{}
.room--bedroom{}
.room--bathroom{}
집에 몇개정도의 다양한 타입의 방이 있다고 친다면 그 방들엔 비슷한 특징들이 있을겁니다
즉 모든 방엔 마루와 천장 벽 문이 있을거예요.
거기에 공통적인 특징의 정보를 추상한게 .room{}
클래스로 모든 속성을 공유할겁니다.
그리고 각각의 방을 자세히 살펴보면 또 다른점도 있지요.
부엌은 타일이 붙은 마루에 침실은 카펫이 깔려있을지도 모르고 욕실은 창문이 없을것이고 침실엔 창문이 있을거예요.
또한 각각의 방의 벽들은 다양한 색으로 다르게 칠해져 있을 거예요.
오브젝트지향CSS에 의하며 기본적인 오브젝트는 공통의 스타일을 지정하고 구체적인 클래스로 들어가면 기본 오브젝트를 확장 한 유니크한 특성을 정의하도록 하고 있습니다.
이걸로 대량의 컨포넌트를 따로따로 작성 하지 않고 컨포넌트간의 반복적인 디자인 패턴을 끄집어 내어 재사용가능한 클래스로써 추상화 해볼 수 있습니다. 결국 뼈대가 되는 기본「오브젝트」을 만들고 그 위에 기본오브젝트의 추상화한 클래스를 정의합니다. 그리고 이 클래스를 확장해서 보다 유니크한 상세스타일을 정의하는 겁니다.
혹시 새로운 컨포넌트를 작성할 경우엔 그 컨포넌트의 뺘대와 피부부분을 나눠보세요. 컨포넌트의 뼈대는 구축시의 재사용을 고려하여 범용적인 클래스를 사용합니다. 그리고 보다 구체적인 클래스로 피부부분을 정의하여 디자인 요소를 집어 넣으면 됩니다.
컨포넌트를 새롭게 만들 경우 가로폭에 별도의 제한을 두지 않아도 됩니다. 풀 레이아웃이 가능하도록 하고 컨포넌트를 집어 넣는 쪽의 가까운 요소나 그리드시스템이 가로폭을 결정하도록 둡시다.
높이는 절대로 설정하는게 아닙니다.
높이는 (이미지나 스프라이트 같은)사이트에서 _표시하기전에_사이즈가 정해진 것에 대해서만 적용하는 겁니다.
혹여라도 p
라던지 ul
, div
이런것들에 높이를 설정해서는 안됩니다.
높이를 조절하고 싶을때는 line-height
를 사용하는 걸로 유연하게 대처가능할겁니다.
그리드 시스템은 선반이라고 생각되어집니다. 무언가의 내용물을 집어 넣으니까요. 사실 그리드시스템자체의 역할은 없으니까요. 그리드시스템을 사용한다면 당신은 그 중심에 재료를 채워 넣으면 됩니다. 스타일은 그리드 _안에_요소에 대해서 적용합시다. _어떤_상황에 있어서도 절대 박스모델의 속성을 그리드를 구성하는 요소에 적용해서는 안됩니다.
저는 UI사이즈 조정에 몇개인가의 방법을 맞춰 사용하고 있습니다. 퍼센트(%), 픽셀(pixel)、, 문자폭(em, rem)을 사용하고 이외의 방법은 전혀 사용하고 있지 않습니다.
그리드시스템에서는 이상적인 방법으로 퍼센트로 설정하면 좋습니다. 그리드시스템을 컬럼 폭이나 페이지 레이아웃에 제어하는 걸로 컨포넌트가 자유롭게 사이즈를 조정하며 여백을 남기는게 가능합니다(좀전에 얘기했습니다) 폰트사이즈에 대해서는 rem단위을 사용하고 예비 방법으로써는 pixel지정을 병행합니사 이 방법은 em단위에 의한 유연성을 확보하면서 동시에 픽셀지정으로 백업하는 걸로(픽셀폴백)신뢰감을 얻을 수 있습니다. 여기선 Sass를 사용해서 rem과 픽셀폴백을 실행한 예를 보여드리겠습니다. (여기 예에서는 베이스 폰트사이즈($base-font-size)가 어딘가에 지정되어 있다고 칩시다)
@mixin font-size($font-size){
font-size:$font-size +px;
font-size:$font-size / $base-font-size +rem;
}
저는 사전에 지정한 정의에는 픽셀단위밖에 지정하지 않았습니다. 이미지등의 절대적으로 픽셀사이트가 정해진경우에도 픽셀을 지정해 사용합니다.
저는 그리드시스템에 맞춰 문자의 사이즈에 관해 일련의 클래스를 정의했습니다[※1]。 이 클래스는 Double stranded heading hierarchy 방식으로[※2] 스타일의 적용을 하고 있습니다. 이 방식에 대한 구체적인 저의 다른 포스트[Pragmatic, practical font-sizing in CSS] (http://csswizardry.com/2012/02/pragmatic-practical-font-sizing-in-css)를 참조해주세요
[※1] :해더、푸너、사이드바 등에、여러가지 문자의 사이즈를 조절하는 일입니다. [※2] :논리적인 표현 구조와 물리적인 표현 구조의 사이즈를 복잡하지 않게 간단히 설정하는 방법입니다. 상세한 링크는 좀전에 참조를 봐주세요.
CSS의 생략기법은 주의해서 사용해주세요。
CSS속성의 정의에는 background:red;
처럼 짧게 쓰는 매력적인 방법이 있습니다만
이렇게 써버리기 시작하면 「나는 배경으로 이미지는 없지만 본문과 같은 스크롤러 좌측위의 x-y방향으로 반복적으로 들어가고 배경색은 빨강으로 좋아요」라고 지정해 버리는 것과 같습니다.10회동안 9회는 그걸로 그다지 문제가 없을지도 모르지만 남은 1번에 큰일이 벌어질지도 모릅니다. 생략기번이란게 쓰란거냐 말란거냐란 생각에 좀 열불이 나기도 합니다.
확실하게 background-color:red;
라고 적어 주세요.
단지 요소의 아래 여백에만 설정하고 싶었다면 margin-bottom:0;
라고 적는게 최고입니다.
같은 식으로 margin:0;
은 짧은게 편리 합니다만 좀 더 명시적으로 써줘야합니다
실제로 요소의 아래만 스타일을 설정하고 싶다면 margin-bottom:0;
라고 써주는게 제일 적절합니다.
CSS의 속성은 명시적으로 써주고 생략기법은에따라 의도없이 속성이 설정되지 않도록 신경써야 합니다.
결국 요소의 아래부분의 여백만을 없애고 싶은 경우인데도 사각 외각의 여백을 전부 margin:0;
로 없애버리는건 정말 넌센스지요.
생략기법은 좋기는 하지만 간단히 오용하고 마는 경우가 많습니다.
우선 셀렉터의 일반론에 들어가기 전에 CSS의 ID에 대해서 주의해야할게 있습니다. 절대로 CSS의 ID셀렉터는 사용해서는 안됩니다
JS와의 연계를 위한 마크업과 요소의 지정을 위해 ID사용이 가능하긴 합니다만 스타일의 설정에는 클래스를 사용해주세요. 여러분도 한 곳밖에 사용하지 못하는 스타일을 스타일시트에 두고 싶진 않으시겠죠!
클래스에는 재이용성과 이점이 있고 (우리가 원하든 원하지 않든) 클래스에는 뛰어난 저상세도(low specificity / 역주: 여러장소에 사용가능한 성격)이 있습니다 상세도를 낮게 가지는건 절대적인 의무입니다. 한개의 ID는 한개의 클래스보다도 255배나 적은 영역에 밖에 지정하지 못하기 때문에 앞으론 절대 영원히 CSS에서 사용하지 않도록 해주세요.
셀렉터는 되도록 짧고 효율적으며 또한 이식성 좋게 신경써가며 사용해 주세요.
무거운 자손셀렉터(location-based selectors)는 몇가지 이유에 의해 피해야할 것들입니다,
예를들어 .sidebar h3 span{}
라는 셀렉터에 대해 생각해보죠
이 셀렉터는 자손의 지정이 많으므로 스타일을 유지한채 span
요소의 스타일을 .sidebar
의 h3
의 안에 지정하는것 이외에 이동하는게 불가능합니다,
너무긴 셀렉터는 퍼포먼스의 문제도 일으킵니다,
즉 셀렉터의 체크수가 너무 많아지죠(예를들어.sidebar h3 span
라면 3회 .content ul p a
라면 4번의 체크가 발생합니다.)
브라우저에게 큰 부담을 지워버립니다.
스타일은 되수있는한 특정 자손요소에 의존하지 않게 하고 짧고 좋은 셀렉터가 되술 있드록 신경써야 합니다.
전체적으로 셀렉터는 짧게 하도록 의식적으로 작업해야합니다만 (예를들어 클래스 계층은 한개만 하거나)
클래스명 자체는 필요한경우라면 길어도 상관없습니다. .usr-avt
보다는 .user-avatar
쪽이 더 좋습니다.
**기억해주세요:**클래스명은 의미도 무의미도 아닙니다. 기능적인가 그렇지 않은지가 중요합니다. 클래스명에 콘텐츠위의 의미를 부여하는것은 관두고 기능성과 장래성을 생각해 이름을 붙입시다.
이제까지의 논리를 돌아봐도 제한셀렉터는 그리 좋지않다는걸 알수 있습니다.
div.promo
좌측같은경우는 과도하게 제한한 셀렉터입니다.
.promo
다음과 같이 적는 것만으로도 같은 결과를 이끌어 낼 수 있습니다.
물론 그때그때 의도적으로 제한한 클래스명을 사용하고 싶은 때가 있습니다만,
(결국 .error
라는 범용적인 클래스가 있다고 치고 특정요소에 수정하고 싶을 경우 (이런 느낌입니다 .error{ color:red; }
div.error{ padding:14px; }
))、
일반적으로 피해야합니다.
별도 과잉한정셀렉터의 예로 ul.nav li a{}
라는게 있습니다.
이것도 순수한 ul
없애는게 가능합니다 왜냐면 저희는 .nav
는 리스트 요소라는걸 알고 있으므로 a
요소는 반드시
li
안에 있을것이기 때문에 최종적으로 ul.nav li a{}
는 .nav a{}
처럼 고쳐쓸 수 있습니다.
브라우저가CSS의랜더링의 속도를 향상시키는것은 사실입니다만
효율은 당신이 신경쓰고 처리하면 어떻게든 되는 부분입니다.
짧게 들여쓴 셀렉터를 사용합시다.
유니버셜 셀렉터 (*{}
)를 키셀렉터 (※3)로써 사용해서는 안됩니다.
또한 CSS3의 복잡한 셀렉터를 피하는것도 문제를 피하는데 도움이 됩니다.
[※3] 셀렉터의 경우 가장 오른쪽에 기재되는 셀렉터를 키셀렉터라고 부릅니다.
DOM에서 특정요소를 지정하는 셀렉터를 사용하는 대신
스타일이 필요한 소스에 직접 클래스를 쓰는 편이 편한 경우가 종종 있습니다.
.header ul{}
라는 셀렉터의 예를 생각해봅시다.
문제의 ul
요소를 우리들이 만드는 웹사이트의 메인네비게이션에 비유해 봅시다.
ul
요소가 해더의 중간에 있고 거기에 ul
요소밖에 없다고 했을때 좀전의 셀렉터도 잘 움직일겁니다.
그러나 이게 이상적인 적절한 셀렉터라고는 말할 수 없습니다.
유지보수를 생각하지 않더라도 셀렉터로서 요소를 적절하지 지정하기 어려운 상황이 있긴 할겁니다.
이런 상황에 별도의 ul
요소를 해더의 추가하면 의도하지 않던 네비게이션용 스타일이 적용되어져 버립니다.
이렇게 되면 대량의 코드 리팩토링을 해야하든가 .header
내의 별도 추가한 ul
요소의 네비게이션의 스타일을 지워야하는 상황이 생겨버립니다.
셀렉터의 의도는 무엇을 스타일링하느냐는 목적에 따른 의도와 일치하지 않으면 안됩니다.
아래와 같이 한번 스스로에게 물어보세요.
「나는 이 요소를 .header
내의 ul
이라 선택한것인가? 아니면 웹사이트의 메인 네비게이션 이라 선택한건가?」
이 질문의 답에 따라 당신의 쓸 용도에 맞는 셀렉터가 선택되어질 것입니다.
키셀렉터는 요소의 타입을 지정하거나 추상오브젝토의 클래스를 지정해버리는 것처럼 사용하지 말아주세요.
.sidebar ul{}
나 .footer .media{}
와 같은 셀렉터를 테마용의 스타일시트에서 굳이 보고 싶지는 않을 것입니다.
어찌됐든 명시적이어야합니다. 결론은 적절한 효과를 보고싶은 요소에 맞춰 사용해야합니다. 이 부모요소는 아닙니다 또한 마크업이 바뀔것을 미리 생각하고 제작하여서도 안됩니다 현재 어쩌다 그냥 그렇게 만드는게 아니라 꼭 필요한 요소에 맞춰 셀렉터를 사용해야합니다.
여기 정리되어져 있는 저의 기사가 있으니 꼭 참조해주세요. Shoot to kill; CSS selector intent
!important
을 서포트적으로 사용하는건 좋습니다.
!important
을 붙이는 것만으로 우선적으로 인식하는걸 완전히 자각하고 있다면
강압적으로!important를 붙여도 나쁘진 않습니다. 예를들어
.error{ color:red!important }`같은 겁니다.
!important
을 시행착오용으로 사용하는건 (CSS가 꼬여서 어떻게든 하고 싶을때) 그닥 추천하지 않습니다.
CSS를 고치고 셀렉터를 리팩토링가능하게 해보면서 이 꼬인 문제를 어떻게는 해결하려고 해보세요
셀렉터는 짧게 하고 ID를 피하는것 만으로 이런 경우의 문제는 대부분 해결됩니다.
매직넘버는 정도「이정도면 어떻게든 되겠다」라는 이유에서 사용하는 숫자입니다. 왜 그것이 잘움직이는게 정말로 주로 미래성이 없는지 유연성과 관용성이 없기 때문에 좋지 않은 일입니다. 문제의 적절한 해결이 아니라 대처방안같은 것입니다.
예를들어 네비게이션요소의 아래에 드롭다운요소를 움직이기 위해
.dropdown-nav li:hover ul{ top:37px; }
라는 코딩을 하면
37px이라는 매직넘버가 나오기 때문에 좋지 않습니다.
이런경우 .dropdown-nav
의 요소가 37px의 높이에서 밖에 제대로 움직이지 않습니다
대신 .dropdown-nav li:hover ul{ top:100%; }
라고 코딩하면
.dropdown-nav
이 어떤 높이에 있어도 드롭다운요소는 네비게이션 요소의 위에서부터 높이 100%의 위치에 표시됩니다.
수치를 직접 코딩하고자 하는 경우 매번 2번정도는 잘 생각해주세요.
즉 키워드나 별도지정(예를들어top:100%
라는건「위에서부터 높이 100%의 높이」라는 별도지정)이
사용할지 있는지 없는지 전부 수치를 지정하지 않고 사용할 수 있는 방법이 없는지 잘 생각하고 작업하세요.
전부 하드코딩한 수치는 반드시 필요하지 않은 노력일 수 있습니다.
IE용 스타시트는 대체로 피하는게 가능합니다.(굳이 따로 작성하지 않아도 됩니다) IE용 스타일시트가 필요한 경우는 기능부족을 문제를 피하기위해서 입니다.(PNG투명도 조정같은거죠)
일반적으로 IE용 스타일시트가 없어도 전부의 레이아웃의 룰이나 박스모델은 CSS를 고치는걸로 제대로 보여지긴 합니다. 이건 결국
<!--[if IE 7]> element{ margin-left:-9px; } < ![endif]-->
요런 코드나 단순하게「어떻게든 해보이겠다」라는 식의 마구잡이로 끝내는걸 의미합니다.
만약 CSS에 문제가 부딪혔다면 그 문제를 수정하고자 한다면 무엇가 추가하기전에 코드를 삭제합시다 이미 써진 CSS에 문제가 있어서 그 CSS에 무언가 추가하고자 한다면 그건 바른 해결책이라고 할수 없습니다.
문제가 없어지기 전에 의심되는 마크업과 CSS를 삭제하는 걸로 어느 코드에 문제가 있는지 알수 있을 겁니다.
이상한 레이아웃의 움직임을 없애기 위해 어딘가에overflow:hidden;
을 넣고싶은 유혹에 시달리지도 모르겠습니다만 대부분의 경우 overflowは는 문제가 아닙니다. 결국 증상을 개선할게 아니라 우선 문제를 제대로 파악하고 해결합시다
저는 프리프로세서로써 Sass를 사용하고 있습니다 프리프로세서는 엄격하게 사용합시다 Sass는 CSS를 보다 파워풀하게 사용하기 위해서 순서에 맞는 구조를 망치는(자식셀렉터를 남용한다)일은 피합시다. 순서에 맞는 구조라는 것은 프리프로세서를 사용하지 않고 CSS를 쓰는 경우에도 문제가 없는 경우만입니다. 결국
.header{}
.header .site-nav{}
.header .site-nav li{}
.header .site-nav li a{}
이런 작성법은 지금까지의 배운걸 준으로 봤을 때 통상적인 css로써 전혀 필요가 없으므로 Sass에서 아래와 같이 적는 것은 절대 안됩니다.
.header{
.site-nav{
li{
a{}
}
}
}
만약에 Sass에서 다음의 예를 적을때는 아래와 같이 해주세요.
.header{}
.site-nav{
li{}
a{}
}