웹을 떠받치는 기술은 모두 비슷한 사정이지만, 특히나 CSS 작성 결과물은 개개인의 코딩 습관과 숙련도 그리고 유동적인 브라우저 지원 상황에다 반갑지 않은 버그 등 여러 외적 요인이 모여서 큰 변수로 작용하기 마련이다. 표면적으론 단순해 보이지만, 자유의지에 맡겨진 properties 지정 작업은 픽셀 하나하나 차곡차곡 쌓아 올린 작용과 반작용의 만남이다. 이것은 잔잔한 브라우저 창에 파도의 물결을 일으키는 상상력의 실현이 될 수도, 혹은 의도치 않은 부작용 때문에 엉키고 뒤틀려버린 혼란의 골칫거리가 되버릴 수도 있다. 그래서 항상 집중과 주의가 요구되는 고난의도 작업.

이런 복잡 미묘한 상황에 조금이라도 외적 잡음을 줄이고 동시에 CSS 작성의 효율을 높이고자 OOCSS, SMACSS, BEM과 같은 여러 구조적 방법론들이 계속 등장하고 있으며, 또한 공동 작업의 편의를 위한 CSS 코딩 스타일 통합을 목적으로 properties 지정 순서에서부터 공백의 개수, 따옴표 스타일 등 아주 세세하고 민감한 부분까지 일관되게 정리해주는 CSS 빗질 도구까지 마련되어 있다.

여기서 한발 더 나아가 SASS, Less와 같은 일명 Pre-Processor의 힘을 빌려 CSS 작성 효율을 구조적으로 좀 더 끌어올리려는 노력도 활발한데, 최근엔 한술 더 떠서 CSS 후처리 과정까지 더해준 Post-Processor들도 덩달아 비 온 뒤 잡풀처럼 여기저기 생겨나고 있어서 이들의 태생 목적과 사용법을 소개하고자 한다.

CSS Pre-Processors vs. Post-Processors

CSS Pre-Processor는 기존 CSS 문법의 확장 성격으로 자기만의 syntax로 작성하고 parse/compile 과정을 거쳐 일반 CSS로 되돌려준다. 이에 반해 Post-Processor는 그냥 맨살의 CSS 문법으로 작성된 것을 해석/처리해서 다시 일반 CSS를 돌려주는 차이가 있다.

정의만 살펴보면, Post-Processor를 써서 얻을 수 있는 장점을 이해하기 힘든데, Post-Processor가 제공하고 있는 기능 중 가장 많이 애용되는 Autoprefixer의 사용 예를 보면 Post-Processor만의 장점이 뚜렷해진다.

CSS3 규칙 중 브라우저 지원 때문에 prefix를 일일이 붙여줘야 하는 상황이라면, Sass(SCSS)의 경우 mixin 기능으로 다음과 같이 적용해 줄 수 있다.

@mixin flexbox() {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
}
 
.box {
  @include flexbox();
}

하지만 Autoprefixer의 힘을 빌리면 CSS 작성은 아주 단순해진다.

.box { display: flex; }

원래의 CSS 문법을 그대로 작성하면, 후처리 과정을 거쳐 골치 아픈 vender prefix를 더해 다음과 같이 돌려준다.

.box {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
}

특정 CSS property의 브라우저 지원 상황을 일일이 확인해 가면서 mixin을 써야 할지 말아야 할지 고민할 필요가 없는 것이다.
Post-Processor(PostCSS) 소개 슬라이드: PostCSS: the Future after Sass and Less

Post-Processor를 이용한 깔끔하고 미래 지향적인 CSS 작성(이)란 제목의 글 마저 읽기 →

CSS3에서 새로 소개된 rem(root em) unit은 em unit과 마찬가지로 상대성을 띤 Relative length units 중 하나지만, 기존 부모 요소를 기준으로 한 em unit과 달리 root element, 그러니까 html element를 기준으로 그 크기 값이 정해지면서 부모 요소의 중첩으로 생기는 뻥튀기의 부작용을 걱정할 필요가 없다는 것이 장점이다.

그래서, 어느 하나의 요소를 기준으로 또 다른 요소의 상대적 크기를 정해주고 싶을 때 많이 사용되는데, 문젠 언제나 그렇듯 IE < 9을 포함해서 아직 만족스럽지 못한 rem unit의 브라우저 지원 상황을 고려해서, 미지원 브라우저에서도 인식되도록 적절한 대응 값을 함께 정의해 줘야 하는 성가심이 있다.

이런 상황에서 SaasLESS 혹은 Stylus와 같은 CSS pre-processor의 힘을 빌린다면 효율적인 CSS 작성에 큰 도움이 된다는 것은 이미 잘 알려져 있다. 하나의 좋은 본보기로, CSS pre-processor를 써서 rem unit의 fallback을 구현한 예.

한편 아래는 실험 삼아 지금 한창 논의되고 있는 CSS VariablesCalc() function만을 써서 rem unit의 fallback을 구현해 보았는데, 여기에 꼭 안성맞춤으로 CSS polyfill임을 자처하면서 지금 한창 개발중인 또 하나의 CSS preprocessor인 Myth의 힘을 빌려서 바로 적용해 보았다.

:root {
  var-base-font-size: 10;
  var-body-font-size: 14;
  var-heading1-font-size: 18;
}
 
html {
  font-size: calc(var(base-font-size) / 16 * 100%);
}
 
body {
  font-size: calc(0px + var(body-font-size));
  font-size: calc(0rem + var(body-font-size) / var(base-font-size));
}
 
h1 {
  font-size: calc(0px + var(heading1-font-size));
  font-size: calc(0rem + var(heading1-font-size) / var(base-font-size));
}

이렇게 작성된 CSS는 Myth를 통해 다음과 같이 변환된다.
CSS Variables와 Calc() function을 써서 rem unit의 fallback 구현하기(이)란 제목의 글 마저 읽기 →

.아빠-엄마 {
  margin: 0;
  padding: 0;
  background: skyblue;
}
.아빠-엄마__자식 {
  background: inherit;
}
.아빠-엄마__자식:last-child {
  font-weight: lighter;
  font-size: small;
}
.아빠-엄마__자식--예쁜-딸래미 {
  color: pink;
}
.아빠-엄마__자식--개구쟁이-막내 {
  color: tan;
  transform: skewX(30deg);
}

여기서 개구쟁이 막내는 특별하게 .아빠-엄마__자식--개구쟁이-막내란 class를 따로 지정해 줄 필요 없이 CSS pseudo-class:last-child만 써서 처리해 줄 수도 있었지만, 워낙 개구쟁이라 어쩔 수 없었다는 소문이…

추가 참고 문서:

CSS를 작성하다보면 스타일 정의 갯수가 증가함에 따라 주의를 한다고 해도 분명 얘기치 않게 중복된 스타일 선언을 하기 마련이다. 물론 나중에 최적화 과정에서 CSS 파일을 minimize 하게 되면 파일 크기에 큰 영향을 끼치진 않겠지만, 나중에 관리적인 측면에서 불필요하게 덤으로 정의된 스타일은 상당히 귀찮아질 수가 있다.

csscss는 이렇게 CSS 파일을 해석해서 덤으로 중복되게 정의된 스타일 선언을 꼭 집어서 보여주는 도구인데, Ruby gem으로 배포되고 있으며 설치는 다음과 같다.

$ gem install csscss

csscss – CSS 파일에서 중복 정의된 스타일을 꼬집어주는 도구(이)란 제목의 글 마저 읽기 →

가령, CSS3 애니메이션 효과를 적용할 때 미지원 브라우저한테는 대신에 JavaScript를 써서 애니메이션 효과를 대체하려고 할 때 유용한 gist로 jQuery plugin 형태로 다음과 같은 것이 있다.

$.support.cssProperty = (function() {
  function cssProperty(prp) {
    var b = document.body || document.documentElement,
    s = b.style;
 
    // No css support detected 
    if(typeof s == 'undefined') { return false; }
 
    // Tests for standard prop 
    if(typeof s[p] == 'string') { return rp ? p : true; }
 
    // Tests for vendor specific prop 
    v = ['Moz', 'Webkit', 'Khtml', 'O', 'ms', 'Icab'],
    p = p.charAt(0).toUpperCase() + p.substr(1);
    for(var i=0; i<v.length; i++) {
      if(typeof s[v[i] + p] == 'string') { return rp ? (v[i] + p) : true; }
    }
  }
 
  return cssProperty;
})();

출처 – Extends the jQuery.support object to CSS Properties

처음부터 무조건 JavaScript를 써서 애니메이션 효과를 주지 않는 이유는, 당연 CSS3 애니메이션 효과를 지원하는 브라우저에선 더 매끄러울 테니까 그렇다.
사용 예: CSS3 Dropdown Menu – CodePen