Xenosium 2018 Redesign
citrus*paradisi
XENOSIUM 8th DESIGN REVISION
OCTOBER 2018
2018년 10월 4일을 기준으로 블로그의 디자인을 바꿨다. 정확히 따지자면 레이아웃은 그대로고 색상만 바뀐거긴 하지만, 배경색까지 반전이 되어서 체감은 꽤 큰 변화로 느껴지는 듯. 작년 10주년을 기념으로 디자인한 본 테마를 얼마나 오래 유지할지, 1년이 더 지난 시점에서 색상만 바꾸는 식으로 갈지 고민을 하다가, 최근에 macOS의 최신 버전인 Mojave에 들어간 “다크 모드” 옵션을 키고 쓰다보니 웹사이트도 어두운 배경이면 프레임과 잘 어울리겠다는 생각이 들더라. 어차피 테마에 지정된 색은 전부 LESS 변수로 선언되어있는지라, 변수의 실제 색상 값만 바꾸고 스타일시트를 컴파일하는것만으로 사이트 전체의 색상을 손쉽게 바꿀수 있기 때문에 한번 해보고 어떤지 보자 하고 시도했던게 꽤 썩 마음에 들어서 실제로 적용하는데까지 이르렀다.
만지는 김에 꽤 많은 곳을 건드렸는데, 기존에 엉성하게 두었던 곳들을 다듬는다든가, 사소한 변경들도 있지만 이곳저곳에 눈에 띄는 효과들이 많이 추가됐다. 기능 면에서 편리하거나 그런 개선이라기보다는 그저 보기에 멋있는걸 많이 넣었다. 가령 페이지를 처음 로드할 때에만 보이는 약간 더 화려한 헤더 로고 애니메이션이라든가, 링크를 클릭했을때 페이지가 넘어가기 전에 클릭한 걸 깜빡여 피드백을 준다든가.
이 블로그는 애초부터 내 놀이터라는 생각이라 회사에서의 작업물이나 다른곳보다도 더 고삐를 풀고 각종 CSS 애니메이션이나 효과를 적극적으로 써온 감이 있다. 다만 특정 액션이나 조건에 묶여 트리거되는 애니메이션은 CSS뿐만 아니라 자바스크립트를 어느정도 할줄 알아야 가능한데 (뭘 눌렀을때 CSS 클래스를 언제 어디다 붙여서 그 클래스에 선언된 애니메이션을 재생하게 해라- 라는식의 동작) 내가 거짓말 아니고 자바스크립트는 진짜 그냥 코드 예제 보고 이름만 바꿔서 응용하는게 전부인 실력이었던지라 이제까지는 내가 생각한걸 실제로 동작하는 코드로 짜는건 매우 힘들어서 엄두를 잘 내지 못했다.
그렇다고 그간 딱히 자바스크립트를 각잡고 공부했냐… 하면 그건 아니지만 그래도 회사일하고 맨날 남이쓴 코드 보고 자꾸 삽질하고 하다보니 어느정도 머리속에 자바스크립트 코드라는게 어떤 식으로 굴러가는건지 예전보다는 조금이나마 감이 잡히는 모양인지 이번에 스킨 고치면서 이것저것 해보니 생각한대로 되더라. 소소한 성취감! 그렇다 해도 아직 바닐라 js도 아닌 jQuery기반의 코드라 내세울만한건 못되지만… 아무튼 그렇게 조금이나마 더 진보한 것 같은 느낌을 받아서 기분이 좋았다.
컬러테마
기존의 컬러는 강한 레드/오렌지색과 녹색을 조합한 다소 파격적으로 대비되는 매칭이었는데, 배경색을 뒤집고나서 포인트컬러 두개를 어떤걸로 할까 고민하다가 일단 기존의 빨간색은 꽤나 마음에 들은지라 대강 그쯤에서 너무 멀리가지 않은 색으로 그대로 쓰고싶은 생각이 들었다. 결국 빨강보다 약간 핑크쪽으로 치우친 자주색이 되었다. 이제 보조색으로 기존의 녹색을 대체할 색상을 찾다가, 대비되는 색이 아닌 이웃색인 오렌지색으로 골랐다. 고르고 나서 보니 이거 색 조합이 완전…
citrus paradisi는 자몽(grapefruit)으로 알려진 이 과일의 학명이다. 오랜만에 디자인에 이름을 붙여봤다. (정작 이번 minor revision의 기반이 된 메인 디자인은 이름이 없었는데!) 페이스리프트랄까, 마이너한 수정버전이지만 그래도 생각 외로 작업하는데 시간과 노력을 많이 들였기 때문에 그 공로를 기리고자 이에 8번째 디자인의 칭호를 수여하노라. 지난 10주년 기념 디자인을 xnsm10로 이름붙이면서 6에서 숫자가 10으로 점프해버리면서 마치 모 휴대폰 메이커와같이 말이지 카운트가 리셋되나 싶었는데 사실 리셋 안하고 6->7->8로 온 것이었다! 짜잔~ 반전의 반전.
여담으로 본문 배경이 어두운 색에 텍스트 색이 흰 색인 스킨을 쓴건 2009년 이래 무려 8년만의 등장이다. 2009년에 런칭한 imaginCANVAS라는 이름의 디자인을 기점으로 지금까지 계속 밝은 배경의 테마였기 때문에.
헤더 애니메이션 어떻게 한거에요?
(못 봤다면, 새 탭을 열고 xenosium.com을 쳐서 접속해보면 보인다)
원래는 폰트가 로드되기 전에 스타일링되지 않은 “xenosium” 문자가 먼저 보였다가 잠시후에 뜩 하고 바뀌는게 보기싫어서, 그냥 메인 로고와 같이 SVG로 만들어서 html에 박아버리자-라는 계획에서 시작했었다. SVG를 html에 인라이닝하는 것의 가장 큰 장점은, 외부 리소스를 별도로 요청하지 않아도 되니 시간이 절약된다는 점에 더해 CSS로 SVG 그래픽 내의 모든 도형을 하나하나 타겟해서 스타일을 바꾼다든가 애니메이션을 넣는다는 등의 컨트롤이 가능해진다는 것이다. 그래서 이 김에 가볍게 아웃라인 애니메이션이나 넣어볼까 생각을 해서 시도해봤는데 꽤 괜찮은 느낌이 됐다.
svg.actual {
stroke: @color-accent;
stroke-dasharray: 150px;
stroke-dashoffset: 0;
fill: rgba(255,255,255,0);
@keyframes strokeanim {
0% {
opacity: 0;
stroke-dashoffset: 150px;
fill: fadeout(@color-accent,100%);;
}
2% {
opacity: 1;
}
20% {
stroke: fadeout(@color-accent,0%);
}
40% {
fill: fadeout(@color-accent,80%);
}
100% {
stroke-dashoffset: 0;
stroke: fadeout(@color-accent,100%);
fill: rgba(255,255,255,1);
}
}
animation: strokeanim 3s both;
}
자주색으로 글자 테두리 선이 그려지면서 마지막에는 fill 색상이 채워지는 애니메이션. SVG 도형의 stroke 기능을 이용한 기법이다. 그다지 엄청 새로운 건 아니긴 하지만, 멋있어보이는데 실제 구현하기에 드는 노력이 얼마 안 들어서 개인적으로 쓰기 좋아하는 효과. 테두리선을 – – – – 점선으로 그릴수 있게 해주는 property가 stroke-dashoffset
(시작점)와 stroke-dasharray
(간격) 두가지인데, 이 둘을 잘 조합해서 대쉬의 간격을 도형 path 전체 길이만큼 값을 길게 설정하고, offset을 같은 값으로 지정한후 서서히 0으로 돌아오게 하면 결국 도형 선 전체를 처음부터 끝까지 “그리는” 느낌이 된다.
또 헤더에 로고마크와 텍스트 사이의 가로줄 패턴도 소소하게 등장 트랜지션 효과를 넣었는데, 이건 예전부터 뭔가 방문할때마다 삼각형의 위치를 랜덤하게 나오게 한다는 등의 아이디어가 있긴 했는데 아무리 생각해도 구현 난이도가 (내 기준으로) 너무 어려울것같아서 손을 못 대고 있다가, 꽤 무식하고 기발한 방법으로 단순한 엔터 애니메이션을 만들었다.
원래의 그래픽은 삼각형 두개가 마주보는 두줄까지만 있었는데, 이걸 4줄로 늘린 뒤에 아래로 갈수록 기존의 배치보다 더 삼각형이 띄엄띄엄 있게 했다. 편리하게도 이쪽 그래픽은 애초부터 변태같게 극도의 최적화를 위해 삼각형 도형을 SVG의 defs
로 지정해놓고 재활용해 좌표만 찍는 식으로 짜놓은지라 기존걸 이용해 새 줄을 추가하는건 어렵지 않았다.
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1280 80">
<style>
.c1{fill:#ff9126}
.c2{fill:#ff135f}
</style>
<defs>
<polygon id="up" points="10,10 20,0 0,0"/>
<polygon id="dn" points="10,10 0,20 20,20"/>
</defs>
<g class="c1">
<use xlink:href="#up" x="0"></use>
<use xlink:href="#up" x="20" class="c2"></use>
<!-- <use xlink:href="#up" x="40"></use> -->
<use xlink:href="#up" x="60"></use>
<use xlink:href="#up" x="80"></use>
<use xlink:href="#up" x="100" class="c2"></use>
<!-- <use xlink:href="#up" x="120"></use> -->
<use xlink:href="#up" x="140"></use>
<!-- <use xlink:href="#up" x="160"></use> -->
<use xlink:href="#up" x="180"></use>
.
.
.
이런식으로 되어있다. 즉 그냥 삼각형을 20px 간격으로 쫙 늘어놓은 뒤에 한줄 코멘트아웃하면 그 칸의 삼각형은 그냥 안 보이게 되는거고. c2 클래스를 붙이면 색이 오렌지색으로.
하여 결과적으로 4줄짜리 sprite animation 시트를 만든 셈이니 이제 이걸 아래에서 위로 4->3->2->1 순서로 움직여주면 마치 삼각형들이 서서히 흩뿌려지는듯한 느낌이 된다.
span {
@keyframes pattern-appear {
0% {
background-position: 0 -30px;
}
33% {
background-position: 0 -20px;
}
66% {
background-position: 0 -10px;
}
100% {
background-position: 0 0;
}
}
animation: pattern-appear 0.7s 1.4s steps(1,end) backwards;
}
폰트를 어떻게 로드해야 잘 했다고 소문이 날까
웹사이트 프레임을 유지한채 실제 바뀌는 부분의 컨텐츠만 ajax로 불러와 바꿔치기 하는 식으로 되는게 가장 끊김없는 경험을 주는 방법이기야 하겠지만, 그렇다고 블로그에 angular이나 react같은 프레임워크를 붙이는건 너무 오버킬이고 (하려고 해도 애초에 내가 못함 ㅋㅋ) 현재의 개별 페이지 로딩 방식에서 최대한 페이지간 이동시에 끊기는 느낌을 줄이기 위해, 초기 페이지 로딩시 가장 비주얼적으로 괴리감을 줄수있는 폰트 로딩+적용 부분을 다듬는데 머리를 많이 굴려봤다.
우선 이 블로그에서 독자적으로 쓰고 있는 Quarion폰트는 내가 데스크탑 이용 및 임베딩 라이선스를 구입한 폰트로, 다른 블로그 asset파일들과 함께 블로그 서버에서 직접 호스팅하고있다. 폰트의 로드과정과 페이지에 적용되는 시점을 더 잘 컨트롤하기 위해 Adobe의 Typekit과 구글이 공동개발한 webfontloader.js를 이용해 로드하고 있다. 폰트를 지정하고 로드하면 html에 폰트로딩끝남! 하고 클래스를 붙여줘서 CSS가 다 로드된게 확실한때 해당 폰트를 먹일수 있게 해주는 거. (폰트가 다 로드되기 전에 이미 font-family
에 해당 폰트를 쓰도록 지정해놓으면 글자가 투명하게 안 나온다든가 깜빡이는 문제가 생긴다)
다만 기왕 폰트 한번 다운로드하는거, 한번 다운로드해서 캐시에 저장됐으면 다시 체크할 필요는 없는데 매번 페이지 로드할때마다 실제 폰트 적용되는데까지 딜레이가 걸리다보니 이게 거슬려서, 방법을 찾다가 sessionstorage (또는 localstorage)에 값을 저장해 폰트가 캐시에 남아있으면 폰트 로딩 체크하는 부분을 건너뛰고 바로 폰트를 먹이게 하는 아이디어를 찾아서 적용했다.
var root = document.documentElement;
(function() {
if (sessionStorage.fontQuarion) {
console.log("Quarion font is already saved in sessionStorage.");
root.classList.add('second-load');
WebFontConfig = {
google: {
families: ['Noto Sans KR:400,700,900:korean', 'Noto Sans JP:400,700,900:japanese']
},
active: function() {
sessionStorage.fontQuarion = true;
}
};
} else {
console.log("Quarion font is not yet saved. Saving to sessionStorage...");
root.classList.add('first-load');
WebFontConfig = {
custom: {
families: ['QuarionWeb'],
urls: ['skin/blog/xnsm10/fonts.css']
},
google: {
families: ['Noto Sans KR:400,700,900:korean', 'Noto Sans JP:400,700,900:japanese']
},
active: function() {
sessionStorage.fontQuarion = true;
}
};
};
(function(d) {
var wf = d.createElement('script'), s = d.scripts[0];
wf.src = 'skin/blog/xnsm10/js/webfontloader.js';
wf.async = true;
s.parentNode.insertBefore(wf, s);
})(document);
})();
(본 페이지의 소스코드 뜯으면 맨 위 head에 인라인으로 들어가있는 코드다)
엉성하게 짠 코드지만 작동은 하더라. 아래부분은 webfontloader.js 문서를 보면 설명되어있는 함수를 부르는 부분이고, 그 위에 간단하게 if else로 케이스를 나눠놓기만 했다. 사실 여기까지는 이미 1년전 리디자인하면서 썼던거고, 이번 개편에서 추가한 부분은 여기에 구글폰트에서 한글/일본어용 폰트인 Noto Sans를 로드하게 하는 부분.
1년전만 해도 구글 폰트에서 Noto Sans가 제공되고 있지 않았기 때문에 (임베딩형식으로) 쓸수가 없었다. 한글폰트는 특성상 용량이 너무 커서 통째로 다운로드하게 하면 트래픽은 둘째치고 페이지 로드 속도가 너무 느려지는 문제가 있다. 폰트가 다 로딩될때까지 기다리게 하면 조금만 느린 환경에서는 몇메가짜리 파일이 다운될때까지 텍스트가 아무것도 안 보이는 참사가 일어나게 되고, 그렇다고 비동기로 나중에 로드하게 하자니 한참 후에 글자모양이 뙇 하고 바뀌는 괴리감이 보기싫고… 이런 문제를 해결하기 위해 개발된 기능이 실제 페이지에서 사용된 문자열만 동적으로 불러오는 dynamic subsetting이라는 기능. 글리프 종류가 많은 CJK폰트를 웹에서 원활하게 사용하는데는 이제는 거의 필수적인 기능이라고 할수 있다.
Adobe가 서비스하는 TypeKit에서는 이 기술을 적용한 ‘dynamic kit’이란걸 가장 먼저 선보여 (2015년 발표 글) 고객들에게 제공했는데, 아이러니하게도 한때 구글과 합작해 만들었던 webfontloader.js 이후에는 각자 독자적인 길을 간 것인지, 해당 다이내믹 서브셋 로딩 기술은 이후에도 webfontloader의 기능으로는 제공되지 않았다. (문서 어디를 찾아봐도 dynamic subsetting같은 옵션은 없다) 그래서 어쩔수 없이 한글폰트는 그동안에는 Noto Sans의 Adobe 버전인 Source Han Sans (한글 글리프는 사실상 똑같다)를 붙여 썼다.
하지만 최근에 구글폰트의 스크립트에도 동적 로딩 기능이 추가됨과 동시에 아시아 폰트가 대량 들어가게 되고, 가장 최근에 Noto Sans 패밀리도 드디어 추가되어, 기존의 Typekit Source Han Sans킷을 갈아치웠다. 호스팅을 구글이 하다보니 좀 더 안정적이고 빠르게 로드할수있다는 장점도 있고. 또 Typekit 쓸 때와 달리 별도의 스크립트를 써서 로드하는게 아니고 기존 webfontloader config에 로컬폰트와 구글폰트를 함께 설정하면 되기 때문에 코드가 더 깔끔해진다는 장점도 있다. (webfontloader에 typekit의 킷 ID를 입력해 로드할수 있는 방법이 있긴 한데, 예전에 테스팅해본 바로는 이쪽은 dynamic kit의 경우는 제대로 로드를 못하는 문제가 있어서 로컬폰트는 webfontloader.js로 로딩하고 타입킷은 자체 스크립트를 또 붙여서 쓰고 있었던 것)
아무튼 그렇게 해서 페이지 로드시 폰트 로딩되는 부분이 이전과 비교해 확연히 더 부드럽게 되었다. 여기에다 이 폰트가 한번 로드 된후에는 저장되니까 이걸 체크하는 걸 이용해서 지금 로드된게 최초 로드인지, 2번째 로드인지를 구분해 html 루트에 클래스를 붙게 하고, 그에 따라 페이지 컨텐츠가 나타나는 애니메이션을 동작시킨다든가 하는 차이점을 두었다. 현재 구현으로는 최초 로딩시에는 메인 화면에서만 약간 더 느긋한 페이스로 헤더 -> 메인 소개 -> 최신 글 순으로 차례로 페이드인된다.
그 외
그 외에도 원래 텍스트큐브 관리 패널 스킨에 포함된 디자인을 따라가던 댓글의 댓글 달기 팝업창을 본 웹사이트 디자인에 맞게 수정한다든가, 댓글 입력창의 내용을 입력하지 않고 전송을 누를때 1차적으로 브라우저단에서 검증을 한다든가 하는 사소한 변경점들도 있다.
암튼 좋음 암튼 그럼
이게 이렇게까지 큰 작업이 되리라고는 솔직히 생각 못했는데 일단 한번 일을 벌려놓고 보니 고쳐야할게 너무 많이 보이더라. 개인 작업이라 기한이 있는것도 아니고 순수 자기만족을 위한 거였던지라 끝까지 갈데까지 가게 된것같다. 뭐 결과적으로는 썩 만족스러운 모습으로 완성이 되어 기쁘지만. 오랜만에 블로그를 들어와서 이리저리 구경하는 재미가 되살아난 느낌이라 기분이 좋다.
최근 며칠간 이것때문에 퇴근하고 집와서 자는 시간이 너무 늦어져서 하루종일 피곤한게 유일한 단점이다
센스가 있으시네요.