웹페이지의 컨텐츠들을 다양한 환경에서 열람을 해도 동일하게 볼 수 있도록 하나의 표현 언어를 생성할 필요성이 생겨나서 HTML이라는 언어가 만들어졌다. 이후 조금 더 커스텀한 서식을 입히고 싶다는 요구에 맞춰 HTML에 서식을 입힐 수 있는 기능이 만들어졌다.
<p>안녕! <strong style="color:red; text-decoration:underline">여기를 빨간색과 밑줄 표기로 강조</strong>하고 싶어</p>
이렇게 태그에 직접 스타일을 입력하는 방식을 inline-style이라고 부른다.
inline-style을 사용하게 되면 원하는 커스텀한 스타일은 사용할 수 있지만, 이러한 부분이 한 군데가 아니기 때문에 매번 반복해서 작성을 해야하는 문제가 생긴다!
<p>이 문장에서 <strong style="color:red; text-decoration:underline">중요한 부분</strong>입니다.</p>
...
<p>안녕! <strong style="color:red; text-decoration:underline">여기를 빨간색으로 강조</strong>하고 싶어</p>
...
<p>새로운 문장에서도 여전히 <strong style="color:red; text-decoration:underline">중요한 부분은</strong>존재합니다.</p>
만약 여기서 빨간색이 마음에 들지 않아서 파란색으로 바꾸고 싶다면 색깔 부분을 일일이 찾아서 빨간색을 파란색으로 바꿔야한다.
이런 과정에서 실수가 발생할 수 있고, 개발자 세계에서 반복 작업을 하게 되는 건 좋지 못하다!
위와 같은 inline-style의 문제점을 해결하기 위해 HTML에서 스타일만 분리해내어 작성하여 반복적인 부분을 일괄적으로 적용해주는 방법을 생각해낸다.
- inline-style이 기록된 부분들을 하나로 묶어 별도의 스타일을 선언(declarations)
- HTML에서 원하는 태그를 찾아서 선택(selector)하여 스타일을 적용
위와 같은 언어인 CSS를 만들게 된다.
선택자(selector)와 선언(declarations)을 합쳐서 CSS Ruleset이라고 부른다.
<p>이 문장에서 <strong>중요한 부분</strong>입니다.</p>
...
<p>안녕! <strong>여기를 빨간색으로 강조</strong>하고 싶어</p>
...
<p>새로운 문장에서도 여전히 <strong>중요한 부분은</strong>존재합니다.</p>
<!-- 컨텐츠에서 스타일을 CSS로 분리해내어 반복을 제거하였다. -->
<style>
strong { color: red; text-decoration:underline }
</style>
이렇듯 CSS는 반복적으로 입력해야 했던 귀찮은 행동들을 대신 해주는 일종의 매크로와 같은 역할을 한다.
CSS는 여러 개의 서식을 일괄적으로 적용하는 방식이다 보니 CSS의 Ruleset의 적용 대상과 서식이 겹칠 경우 어떤 서식을 더 우선시 해야 할지 규칙이 필요하다.
이러한 규칙을 CSS는 Cascade라는 특징을 가지고 만들어졌다. Cascade란 서식을 겹겹이 덧칠해 나가되 단순할 걸 먼저 구체적인 것은 나중에 라는 방법이다. 반복적인 작업을 줄이기 위해 기초가 되는 서식을 먼저 전체에 적용을 하고 점점 더 구체적인 서식들을 적용을 해 나가는 식을 만들면 좋을 거라고 생각한 것이다.
그래서 CSS는 작성된 순서가 아니라 CSS Rule이 가지고 있는 고유의 명시도(Specificity)에 따라 우선수누이가 다르게 적용을 할 수 있도록 설계가 되었다.
이 방법은 코드의 순서를 강제하지 않고 응집력이 높도록 코드를 작성할 수 있도록 도와줄 거라고 생각했다.
/* 아래 4가지 코드는 순서가 변해도 동일한 결과를 나타낸다 */
h1 { font-size: 2em; color: #000; font-family: Georgia}
.small { font-size: 1em }
[href] { color: red; }
#id { color: #ccc; }
/* 순서가 변경이 되어도 위 코드와 결과가 같다. */
#id { color: #ccc; }
.small { font-size: 1em }
h1 { font-size: 2em; color: #000; font-family: Georgia}
[href] { color: red; }
Rule마나 고유한 명시도(Specificity)가 있다는 결정은 결과적으로 아주 좋지 못한 설계가 되었다. 이 설계로 인해 기존의 CSS에서 덮어쓰기를 하기 위해 더 복잡한 Selector를 써야 하고, 복잡한 Selector를 덮어쓰기 위해서는 더 더 복잡한 Selector를 써야 하고, !important
와 같은 우선순위를 변경하는 코드를 남발하도록 만들었다.
추후 설명할 CSS 방법론이나 CSS in JS, Atomic CSS와 같은 기술들은 이러한 한계를 극복하기 위해서 만들어졌다고 생각한다.
웹 산업이 성장하면서 단순히 정적으로 서식과 함께 생성하던 문서에서 데이터들이 결합하여 동적으로 생성을 해야 하다 보니 HTML을 작성하는 주체가 백엔드 개발자가 되었다.
그러면서 게시판, 포럼, 장바구니, 로그인과 같은 기능이 필요한 페이지들은 백엔드를 중심으로 하는 솔루션의 형태로 발전하게 된다. 이러한 이유로 솔루션의 HTML을 CSS를 이용해서 디자인을 커스텀해야 하는 요구사항이 많아지면서 HTML을 건들지 않고 CSS만으로 디자인을 할 수 있는 방법이 중요해지게 된다.
이러한 시멘틱한 HTML을 이용해 하나의 컨텐츠에서 여러가지 CSS의 서식을 입힐 수 있도록 작성하는 것은 HTML5와 CSS3를 제대로 사용하는 하나의 기준이 되었고, 이를 제대로 보여주는 사이트인 CSS Zen Garden이 등장하였다.
CSS Zen Garden은 시멘틱한 원본 HTML이 존재하고 디자이너가 CSS만으로 전혀 다른 스타일을 적용할 수 있다는 것을 보여준다.
(같은 HTML로 전혀 다른 디자인을 만들 수 있다!)
이러한 컨셉을 바탕으로 추후 CSS를 커스텀 할 수 있는 블로그나 워드 프레스와 같은 CMS 서비스들이 인기를 끌게 된다.
다만, 이때까지는 HTML을 먼저 만들고 CSS로 나중에 디자인을 커스텀할 수 있는 방법이 유효했지만, 점점 하나의 웹페이지가 거대해지면서 하나의 컨텐츠를 여러 디자인으로 커스텀 하는 방식보다는 하나의 디자인과 컴포넌트를 중심으로 서비스를 키워나가는 형식으로 발전하게 되었다. 그래서 하나의 HTML에 여러 서식을 넣도록 만드는 이러한 방식은 현대 웹 서비스 개발과는 맞지 않다.
HTML을 수정할 수 없으니 원하는 디자인을 만들기 위해서는 조금 더 정교하고 고도화된 Selector이 필요하게 된다. 그래서 CSS는 점점 더 Selector가 복잡해지는 방향으로 발전을 하게 된다.
이렇게 Selector이 복잡해지면 Specificity가 높아지게 되고 새로운 스타일을 그 뒤에 덮기 위해서는 더 높은 Specificity의 Selector가 필요하고 그러지 못 할 경우에는 !important를 사용하게 되는 부작용이 있어 CSS가 어렵고 복잡해진다는 것이 느껴진다.
Selector를 복잡하게 사용해야 하고 CSS에서 반복해서 사용하는 글자 크기가 색상을 작성을 하고 나서 수정이 용이하지 않다는 점을 해결하고 CSS를 확장하여 사용하고자 하는 시도가 만들어진다.
Nested한 Selector와 variable를 등록할 수 있는 추가적인 문법으로 작성하면 CSS로 변환을 시켜주는 pre-processor인 Sass가 만들어진다.
Sass는 CSS가 가지고 있지 않는 유용한 기능들을 지원한다. 그리고 이 기능들의 존재 목적은 결국 한 가지, 생산성을 위한 것이다. 코드를 빠른 시간 안에 간결하게 작성할 수 있도록 해주고, 코드 수정 시에 신경 써야 할 부분을 최소화해주는 효과도 있다. Sass가 제공하는 기능으로는 변수, 네스팅, 믹스인 등이 대표적이다.
: 부모 루틴 안에서 자식 루틴을 넣어서 싸는 것
ex) 네스팅 적용
<div>
<p>nesting 예시</p>
</div>
div{
p {
color:red;
}
}
이런 식으로 네스팅을 구성하면 다른 컴포넌트에서 사용한 class 이름이 겹치지 않고, 부모 자식 관계로 나타내기 때문에 소스를 수정하거나 속성들을 적용시킬 때 더욱 편하게 느껴질 것이다.
하나의 변하지 않는 컨텐츠와 다양한 변경가능한 디자인이라는 컨셉을 통해 HTML과 CSS에는 시멘틱이라는 것이 중요해졌다.
시멘틱이란 시각적으로 어떻게 보일지가 아니라 의미에 중점을 두는 것이다. HTML이 어떻게 보여질지는 HTML이 결정하는 것이 아니라 CSS에 의해 커스텀 될 수 있어야 재사용성이 커지기 때문이다.
뭐가 더 시멘틱할까?
<div class="error">에러 메시지</div>
<div class="red">에러 메시지<div>
<div class="#ff0">에러 메시지</div>
<style>
.error { color: #f00 }
.red { color: #f00 }
.\#ff0 { color: #f00 }
</style>
동일한 서식을 가지는 .error
, .red
, .#f00
3가지 클래스 이름이 있다.
모두 빨간색으로 표기하는 서식이기 때문에 결과는 같다. 이 중 어떤 이름이 더 시멘틱 한걸까?
.error
라는 이름이 더 시멘틱하다고 생각된다.
이 상황에서 에러 메세지의 색깔을 오렌지색으로 바꿔야 하는 요구사항이 생겼다. (단 HTML은 수정할 수 없다!) CSS를 어떻게 바꾸면 될까?
<div class="error">에러 메시지</div>
<div class="red">에러 메시지<div>
<div class="#ff0">에러 메시지</div>
<style>
.error { color: #f90 }
.red { color: #f90 }
.\#ff0 { color: #f90 }
</style>
.error { color: #f90 }
는 전혀 문제가 없어보인다. 그저 에러색이 오렌지색이 바뀌었다. .red
는 어떨까? 빨간색이 아니지만 그쪽 계열이라고 우겨볼 수 있겠지만,, 파란색으로 바꿔달라고 하면 명백히 잘못된 디자인이다. .#ff0
또한 마찬가지로 명백히 잘못된 디자인을 표기하게 된다.
HTML을 수정할 수 없다면 class의 이름이 시각적인 내용이기보다 의미를 나타내어야 디자인을 커스텀할 수 있는 영역이 다양해진다.
프론트엔드 개발에서 Ajax이라는 혁신과 jQuery의 등장으로 인해 백엔드에서 HTML이 아니라 JSON을 만들게 되었다.
이제는 HTML이 백엔드에 있는 것이 아니라 HTML과 CSS를 함께 작성을 하고 데이터를 연동해서 출력하는 작업을 JS로 하는 방식으로 개발을 하게 된다. 사실상 프론트엔드의 탄생이라고 볼 수 있다!!
이때부터는 HTML과 CSS를 작업하는 주체가 백엔드와 프론트엔드가 나뉘지 않고 점점 프론트엔드로 옮겨지기 시작하면서 복잡한 Selector를 사용해야할 빈도가 줄어들기 시작했다.
HTML의 편집권이 프론트엔드로 서서히 옮겨오기 시작하면서 Selectore를 복잡하게 만들기 보다는 HTML에 class를 추가하는 등의 HTML 수정을 통하여 단순한 Selector를 만드는 방식으로 발전을 하게 된다.
웹사이트에 자바스크립트를 쉽게 활용할 수 있도록 도와주는 오픈소스 기반의 JS 라이브러리이다.
제이쿼리의 특장점은 아래와 같다
페이스북의 성장으로 웹 애플리케이션이라는 영역이 확대되고 Web Framework가 만들어지면서 HTML을 작성하는 주체는 온전히 프론트엔드의 영역이 되기 시작한다. 그러면서 문서 기반이 아니라 컴포넌트 기반의 개발 방식이 자리를 잡게된다. 이렇게 JS의 개념이 발전하게 되면서 프론트엔드는 계속 발전하게 되지만 CSS는 변화의 속도를 따라오지 못하게 된다.
문서를 꾸미려고 만들었지, 앱을 꾸미려고 만든 건 아녔어...
이미 웹 산업은 홈페이지를 넘어 웹 애플리케이션의 세상으로 넘어왔지만 CSS는 예전의 문서를 꾸미기 위한 스펙을 가지고 있었다. 이러한 문제로 인해서 문서를 편하게 꾸밀 수 있도록 설계된 CSS는 문서를 꾸미는 데 있어서는 유용했을 테지만 애플리케이션스러운 UI와 컴포넌트 방식의 개발과는 맞지 않는 설계가 되어버렸다.
모든 문서에 일괄적으로 적용되기 위해서 만들어졌던 기능이 다른 컴포넌트 영역의 스타일을 수정할 수도 있다는 점이 문제가 되었다. CSS는 외부 변화에 의해 너무나 부서지기 쉽다.
HTML을 만들고 CSS를 만들어 두면 이미 만들어진 CSS가 새로운 컴포넌트를 만들기 위한 제약사항이 되어버린다. 새로운 HTML과 CSS를 만들기 위해서는 기존에 만든 CSS를 피해서 작성이 되어야 했다. 때로는 반대로 기존에 만들어진 CSS를 새롭게 덮어써야만 했다.
CSS의 Specificity 관리와 모듈화가 중요해졌지만 CSS의 스펙은 변경할 수가 없었기에 이러한 상황을 이해하고 어떻게 하면 CSS를 잘 작성할 수 있을지 체계적으로 그리고 규칙을 가지고 작성을 해야겠다는 방법론이 논의되기 시작했다.
여러 가지 방법론들이 등장을 하게 된다. 방법론의 본질을 다음과 같다.
- 여러 명이 함께 작업을 할 때 공통적으로 사용할 수 있는 아키텍쳐
- Cascade의 Specificity 관리
- 그러기 위한 이름 짓기 컨벤션!
: Block Element Modifier
seletor은 class 방식으로만 작성하고 네이밍 규칙은 BEM 방식으로 하는 것이 대세 룰이 되었다. 간단한 이름 짓기 컨벤션을 통해 협업할 때 같은 방식으로 이름을 작성할 수 있게 하면서, 구조를 표현하고 Specificity를 하나로만 관리할 수 있게 했다. 기존의 문제점을 해결하고자 하는 방식이다.
<div class="header">
<div class="nav"></div>
</div>
<div class="nav"></div>
<style>
.header .nav { (X) }
/* 이렇게 하면
1. nav가 header 구조에 종속이 되어 nav위치에 따라 디자인이 제대로 나타나지 않을 수 있다.
2. Specificity가 올라가게된다.
*/
</style>
<div class="header">
<div class="header__nav"></div>
</div>
<div class="header__nav"></div>
<style>
.header__nav { (O) } /*
1. 구조도 표현하면서 종속 관계가 없다.
2. Specificity가 하나로 관리된다.
*/
</style>
BEM이 방법론의 최종 승리자가 된 이유!
1. 구조도 표현하면서도 종속 관계가 없다.
2. Specificity가 하나로 관리된다.
3. 그러면서 컨벤션이 단순해서 쉽게 기억할 수 있다.
웹 문서가 아니라 웹 애플리케이션으로 발전을 하는 과정에서 레이아웃을 하기 위한 CSS 스펙에 대한 요구사항은 꾸준히 있어왔다. Flexbox가 나오기 전까지 🔥 float나 table, absolute와 margin 등을 이용해서 억지로 레이웃을 만들던 방법들이 존재했고 이러한 방법들은 대체가능한 방법이 없었으므로 여러가지 Tip과 같은 방법들로 방법이 공유되고 문서가 만들어지게 되었다.
2022년 flexbox는 이제 웹의 모든 레이아웃의 표준이다. float, margin, table, inline-block 등 옛날 방식으로 뭔가 정렬을 하는 방식은 이제 배우지 않으셔도 되고 헷갈려 하지도 마시기 바라며 CSS를 한다면 flexbox만큼은 꼭 master가 되시길 바란다!!
IE는 2015년을 기점으로 현재 더이상의 업데이트가 없다. IE11은 윈도우에서 여전히 높은 점유율의 브라우저였기에 이후 새로운 CSS의 스펙이 나오더라도 개발자들은 사용하기를 꺼려했다. 이때부터 프론트엔드 개발자들의 CSS에 대한 관심이 떨어지는 원인이 되었다.
무엇보다 새로운 스펙이 발표가 되더라도 IE11에서는 지원을 할 수 없기 때문에 해당 스펙을 적극적으로 사용할 수가 없게 되었다.
이러한 이유로 CSS의 스펙이나 CSS에서 문제를 해결하기 보다는 CSS의 문제점을 JS로 해결하려는 시도들이 생겨나기 시작한다!
JS를 사용하여 스타일을 선언적이고, 유지보수 가능한 방식으로 설명한다. JS를 CSS로 전환하는 고성능 컴파일러로, 런타임 및 서버 사이드에서 작동한다.
인라인 스타일과 CSS-in-JS는 같지 않다.
const textStyles = {
color: white,
backgroundColor: black
}
<p style={textStyles}>inline style!</p>
브라우저에서 DOM 노드를 다음과 같이 연결한다.
<p style="color: white; backgrond-color: black;">inline style!</p>
import styled from 'styled-components';
const Text = styled.div`
color: white,
background: black
`
<Text>Hello CSS-in-JS</Text>
브라우저에서 DOM 노드를 다음과 같이 연결한다.
<style>
.hash136s21 {
background-color: black;
color: white;
}
</style>
<p class="hash136s21">Hello CSS-in-JS</p>
CSS-in-JS는 DOM의 상단에 <style>
태그를 추가했고, 인라인 스타일은 DOM 노드에 속성으로 추가했다.
왜 이 문제가 중요할까?
모든 CSS 기능을 JS 이벤트 핸들러로 지정할 수 있는 것은 아니다. 많은 pseudo 선택자도 불가능하고, html, body 태그 등도 지원하지 않는다.
CSS in JS를 사용하면, 손쉽게 모든 CSS의 힘을 그대로 누릴 수 있다. 실제 CSS가 생성되기 때문에, 생각할 수 있는 모든 미디어 쿼리, pseudo 선택자를 사용할 수 있다. 몇 라이브러리는 CSS의 기본 기능이 아닌 것을 지원하기도 한다. (ex. jss나 styled-components)
아주 오랜 시간동안 CSS는 CSS에 작성하고 끝냈다. 문제는 현대 웹은 페이지가 아니라 컴포넌트로 작성되었다는 것이다.
CSS는 컴포넌트 기반의 방식을 위해 만들어진 적이 한 번도 없었다. CSS-in-JS는 이 문제를 정확하게 해결한다.
Tailwind CSS는 Utility-First 컨셉을 가진 CSS 라이브러리이다. 부트스트랩과 비슷하게 m-1
, flex
와 같이 미리 세팅된 유틸리티 클래스를 활용하는 방식으로 HTML 코드 내에서 스타일링을 할 수 있다.
<button class="py-2 px-4 rounded-lg shadow-md text-white bg-blue-500">
Click me
</button>
Utility-First : 미리 세팅된 유틸리티 클래스를 활용하여 HTML 코드 내에서 스타일링
TailwindCSS가 새로운 개념은 아니었다. HTML과 CSS가 만들어졌을 초창기부터 Class에 유틸리한 이름을 붙여 개발하는 방식은 암암리에 행해졌지만, 시맨틱한 방식이 중요한 패러다임이 되면서 이러한 방식은 일종의 꼼수, 옳지 않은 방식으로 여겨졌기에 가급적 피하게 되는 안티 패턴이었습니다.
하지만, TailwindCSS는 이러한 방식을 오히려 일부 차용이 아니라 전면적으로 이러한 방식을 사용하는 것을 권장하며 패러다임 쉬프트에 성공했다.
TailwindCSS가 받아들여지게 된 변화
- 웹 개발은 이제 대부분 솔루션 방식이 아니라 프론트가 직접 HTML과 CSS를 수정한다.
- CSS로 개발하는 것보다 HTML을 다루는 게 더 편하며 사이드-이펙트가 적다.
- 대부분 서비스들이 하나의 디자인 시스템을 가지고 여러 개의 스타일시트를 이용해서 테마를 만들 이유가 없다.
다른 라이브러리들에 비해 기본 스타일 값을 디테일한 부분까지 쉽게 커스텀이 가능하다. 기본 스타일 값을 수정하는 방식이기에 디자인 일관성도 해치지 않는다.
Tailwind CSS는 JS 코드와 완전히 분리되어 있다. 그러므로 프로젝트 진행 도중 JS 프레임워크를 변경하여도 큰 추가 작업 없이 기존의 HTML 코드를 그대로 쓸 수 있다.
<div
class="bg-primary-darken text-bold text-white inline-flex items-center p-4 rounded shadow-md"
>
Not Pretty Code 😵
</div>
직관적이지만 예쁘다고 말하긴 어렵다,,
클래스명을 분기 처리하여 동적으로 스타일링을 설정할 수는 있지만 styled-components와 같이 JS 변수 값에 따라 가로 길이를 설정하는 등의 구현은 가능하기는 하지만 무척 번거롭다!!
2017년 드디어 Grid Layout이 등장하게 된다. 구상은 Flexbox보다도 훨씬 전에 논의도었지만 여러 가지 버전을 거쳐서 공개되었다. 하지만 IE의 시간은 2015년도에 머물러 있었기에 새롭게 만들어진 Grid Layout 스펙과 IE에서 사용 가능한 Grid Layout의 경우 미묘하게 스펙이 달랐다!
그래서 GridLayout은 흥행에 실패한다. 사람들은 골치 아프게 IE11에서 크로스 브라우징을 해야하는 GridLayout에 비해 Flexbox로 충분히 대부분의 레이아웃을 작업할 수 있었기에 Grid Layout은 실험적인 기능에 그치게 되었다.
MS에서 공식적으로 IE11의 지원종료를 발표했다. IE11을 지원하지 않아도 된다는 사실을 못 박은 것이기 때문에, 사람들은 그동안 2015년에 묶여있었던 5년 치의 CSS를 한꺼번에 배워야 했다.
이제는 새로운 CSS의 스펙을 마음대로 쓸 수 있게 되었다. 흥행에 실패했던 GridLayout의 사용 점유율도 10%에서 50%로 올라왔다.