markup-guide

레진 마크업 가이드

레진 마크업 가이드는 유연하고 지속 가능한 코드 작성을 위한 사내 표준입니다. Code Guide by @mdo를 기반으로 상식적인 내용과 장황한 내용은 제거했으며 팀에서 논의한 내용을 추가했습니다.


  1. 기본 규칙
  2. 에디터 설정
  3. HTML
    1. HTML 문법
    2. HTML5 doctype
    3. 언어(lang) 속성
    4. 인코딩 설정
    5. IE 호환모드 설정
    6. CSS, JavaScript 삽입
    7. 속성(attr) 선언 순서
    8. Boolean 속성
    9. 마크업 간소화
    10. 문서 개요(HTML5 아웃라인)
    11. 완벽함보다는 실용성을 추구
  4. CSS
    1. CSS 문법
    2. 속성(property) 선언 순서
    3. 미디어 쿼리 위치
    4. 단일 속성
    5. 전처리문 중첩
    6. 전처리문 계산식
    7. 주석
    8. 클래스 작명
    9. 선택자
    10. 컴포넌트
  5. License

기본 규칙 #

W3C 문법과 레진 마크업 가이드라인을 지켜 코드를 작성합니다. 많은 사람이 참여했더라도 한명이 쓴 것처럼 보이는 코드가 좋습니다. 팀원들과 논의하여 업데이트할 수 있습니다.


에디터 설정 #

규칙을 준수하기 위해 에디터 환경을 설정해 둡니다.


HTML #

HTML 문법 #

<!DOCTYPE html>
<html>
    <head>
        <title>Page title</title>
    </head>
    <body>
        <img src="logo.png" alt="Lezhin">
        <h1 class="hello-world">Hello, world!</h1>
    </body>
</html>

HTML5 doctype #

모든 HTML 페이지 시작 지점에 공백 없이 HTML5 문서 타입을 선언합니다.

<!DOCTYPE html>
<html>
    ...
</html>

언어(lang) 속성 #

문서 루트인 html 요소에 lang 속성을 추가합니다.

<html lang="ko">

인코딩 설정 #

문자열 인코딩을 명시적으로 선언합니다.

<head>
    <meta charset="UTF-8">
</head>

IE 호환모드 설정 #

인터넷 익스플로러가 항상 최신 버전의 레이아웃 엔진을 사용하여 문서를 렌더링하도록 지정합니다.

<meta http-equiv="X-UA-Compatible" content="IE=Edge">

CSS, JavaScript 삽입 #

CSS와 JavaScript를 불러올 때 type 속성을 생략합니다.

<!-- External CSS -->
<link rel="stylesheet" href="code-guide.css">

<!-- In-document CSS -->
<style> ... </style>

<!-- JavaScript -->
<script src="code-guide.js"></script>

속성(attr) 선언 순서 #

HTML 태그 속성은 가독성을 위해 아래 순서대로 작성합니다.

  1. 선택자로 사용하는 id, class 속성은 가장 앞에 선언합니다.
  2. 콘텐츠를 설명하는 alt, title, role, aria-* 속성은 가장 뒤에 선언합니다.
<a id="..." class="..." href="#">Example link</a>
<input class="form-control" type="text">
<img src="..." alt="..." title="...">

Boolean 속성 #

불리언 속성의 값은 지정하지 않습니다.

<input type="text" disabled>
<input type="checkbox" value="1" checked>
<option value="1" selected>1</option>

마크업 간소화 #

모듈화를 고려하여 마크업은 간결하게 작성합니다.

<!-- Not so great -->
<span class="avatar">
    <img src="..." alt="...">
</span>

<!-- Better -->
<img class="avatar" src="..." alt="...">

문서 개요(HTML5 아웃라인) #

섹셔닝 요소와 헤딩 요소를 이용하여 문서 개요를 논리적으로 구성합니다. 섹셔닝 요소(section, article, nav, aside)에는 헤딩 요소를 명시적으로 사용합니다. 명시적 헤딩 기법은 h1 요소를 한 페이지에 한 번 사용합니다. 헤딩 요소만으로 문서 개요를 파악할 수 있어야 합니다.

<!-- Bad HTML -->
<body>
    <h1>동물</h1>
    <div>
        <h1>포유류</h1>
        <div>
            <h1>고래</h1>
        </div>
    </div>
</body>

<!-- Good HTML -->
<body>
    <h1>동물<h1>
    <article>
        <h2>포유류<h2>
        <section>
            <h3>고래<h3>
        </section>
    </article>
</body>

완벽함보다는 실용성을 추구 #

HTML 표준을 준수하고 시맨틱한 문서를 작성하기 위해 노력하기는 하지만 추가적인 노력이 필요하지 않은 범위내에서만 합니다. 최대한 간결한 코드를 사용하도록 합니다.


CSS #

CSS 문법 #

들여쓰기는 공백문자( ) 4개를 사용합니다.

/* 들여쓰기에 tab 문자 사용 안 함 */
{
    property: value;
    property: value;
}

선택자를 그룹핑하는 경우 쉼표(,) 뒤에서 줄바꿈합니다.

/* X */
.selector1, .selector2 { ... }

/* O */
.selector1,
.selector2 { ... }

속성값에는 홑따옴표('')를 사용합니다.

/* X */
[type=text] { ... }
[type="text"] { ... }
{ background: url(ex.png); }
{ background: url("ex.png"); }

/* O: 속성 선택자 속성값에 홑따옴표 사용 */
[type='text'] { ... }

/* O: CSS 속성값에 홑따옴표 사용 */
{ background: url('ex.png'); }

한 줄에 하나의 속성만 작성하고, 마지막은 항상 세미콜론(;)으로 끝냅니다.

/* 속성이 하나 뿐이라면 한 줄에 작성합니다. 여는 중괄호({) 좌우로 하나의 공백, 닫는 중괄호(}) 왼쪽에 하나의 공백을 포함합니다. */
.selector { property: value; }

/* 속성이 둘 이상이라면 속성 기준으로 줄바꿈합니다. 여는 중괄호({) 뒤에서 줄바꿈하고, 닫는 중괄호(})는 새로운 줄에 놓습니다. */
.selector {
    property: value;
    property: value;
}

/* 여는 중괄호({) 앞에는 항상 공백 하나를 포함합니다. */
/* 콜론(:) 뒤에는 항상 공백 하나를 포함합니다. */

다중 속성값들은 쉼표(,) 뒤에 공백 또는 줄바꿈을 포함합니다.

/* 속성값이 길지 않은 경우 한 줄에 표현 */
    { box-shadow: 1px 1px 1px #ccc, -1px -1px 1px #000; }

/* 속성값이 길면 여러 줄에 표현 */
    {
        background-image:
            url('//cdn.lezhin.com/assets/images/header.png'),
            url('//cdn.lezhin.com/assets/images/footer.png');
    }

괄호(()) 안에서는 쉼표(,) 뒤에 공백을 넣지 않습니다.

/* X */
    color: rgba(0, 0, 0, .5);

/* O */
    color: rgba(0,0,0,.5);

축약 가능한 값을 축약합니다.

/* X */
    color: #ffffff;
    font-weight: normal;
    font-weight: bold;
    border: none;
    opacity: 0.5;
    border-width: 0px;
    background-size: 100% auto;
    background-position: 50% 50%;

/* O */
    color: #fff;
    font-weight: 400;
    font-weight: 700;
    border: 0;
    opacity: .5;
    border-width: 0;
    background-size: 100%;
    background-position: 50%;

의미있는 블럭 기준으로 빈 줄을 포함합니다.

/* X: 선택자 또는 속성 사이에 빈 줄 금지 */
.selector1 { ... }

.selector2 {

    property: value;

    property: value;

}

/* O: 의미있는 블럭 기준으로 빈 줄 포함 */
/* 헤더 */
.header { ... }
.header__element { ... }

/* 풋터 */
.footer { ... }
.footer__element { ... }

속성(property) 선언 순서 #

포지셔닝과 박스모델 관련 속성을 가장 먼저 작성하고 나머지는 뒤에 놓습니다.

{
/* Positioning */
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 100;
/* Box-model */
    display: block;
    float: right;
    flex: 1;
    width: 100px;
    height: 100px;
/* Typography */
    font: normal 13px "Helvetica Neue", sans-serif;
    line-height: 1.5;
    color: #333;
    text-align: center;
/* Background */
    background-color: #f5f5f5;
/* Border */
    border: 1px solid #e5e5e5;
    border-radius: 3px;
/* etc */
    opacity: 1;
}

미디어 쿼리 위치 #

미디어쿼리는 관련 규칙이 있는 자리에 모아 놓습니다.

.element { ... }
.element-avatar { ... }
.element-selected { ... }
@media (min-width: 640px) {
    .element { ... }
    .element-avatar { ... }
    .element-selected { ... }
}

단일 속성 #

하나의 속성만 포함한다면 개행하지 않습니다.

/* Single declarations on one line */
.span1 { width: 60px; }
.span2 { width: 140px; }
.span3 { width: 220px; }

/* Multiple declarations, one per line */
.sprite {
    display: inline-block;
    width: 16px;
    height: 15px;
    background-image: url(../img/sprite.png);
}

전처리문 중첩 #

과도하게 중첩하지 않습니다. 선택자 반복을 피하는 용도로만 중첩을 사용하십시오.

/* Without nesting */
.table > thead > tr > th {  }
.table > thead > tr > td {  }

/* With nesting */
.table > thead {
    th {  }
    td {  }
}

전처리문 계산식 #

계산식에 괄호를 사용합니다.

/* Bad example */
.element { margin: 10px 0 @variable*2 10px; }

/* Good example */
.element { margin: 10px 0 (@variable * 2) 10px; }

주석 #

주석은 간결하게 작성합니다. scss 파일은 한 줄 주석(//) 사용이 가능하지만 CSS 파일에 남지 않습니다.

/* Bad example */
/* Modal - Wrapping element for .modal-header, .modal-body, modal-footer  */
.modal {
    ...
}

/* Good example */
/* Modal */
.modal {
    ...
}

클래스 작명 #

/* Bad example */
.sform { ... }
.themeLezhin { ... }
.sf-input { ... }
.sf-btn { ... }
.SearchformButtonDisabled { ... }

/* Good example */
.blockName { ... }                              // Block
.blockName__elementName { ... }                 // Element
.blockName--modifierName { ... }                // Block Modifier
.blockName__ElementName--modifierName { ... }   // Element Modifier

선택자 #

/* Bad example */
section.tweet > header { ... }
section.tweet > header.tweet__header { ... }
.tweet > .tweet__header, .tweet > .tweet__username { ... }

/* Good example */
.tweet { ... }
.tweet__header,
.tweet__username { ... }

컴포넌트 #

/* Modal: modal.scss */
.modal { ... }
.modal__header { ... }
.modal__body { ... }
.modal__footer { ... }
.modal__footer--disabled { ... }

License #

Released under MIT by, and copyright 2014, @mdo and @lezhin