Designing in the Open
How I built this site
To design and code a website from scratch takes time. It looks and feels bare bones for now but I kind of like the simplicity of it. Keep it simple and clean and put more thought into typography and the code. I’ll keep exploring the possibility and to learn more from others.
This post is my attempt to relearn HTML & CSS in practice. They are so simple yet difficult to write at the same time. To educate myself while documenting the process of how I made it happen.
Typography
For the very first step of building this blog, I’d like to set up a set of base typography styles while more than 95% of web design is typography. I agree that almost everything web design does is builds upon the foundation of typography — arranging and aligning text content into a layout. The web is meant for people to read, to navigate, to have access to, even for those who have visual impairment. I’m not entirely sure if I’m doing it the way that I was supposed to, but still worth trying. To maintain visual hierarchy and vertical rhythm for a better reading experience no matter the devices or platforms the user is using.
Typography in practice is not choosing fonts or making fonts, it’s about shaping text for optimal user experience.
Typographic Scale
I’ve been reading a few articles about Typographic Scale. To define a Scale Ratio using CSS Custom Properties for text sizes that applies to headings, paragraphs and spacing for establishing hierarchy. Basically, setting a base --font-size: 1rem
to :root
which is assuming the browser default value is equal to 16px
. Type size for headings <h1>
to <h4>
scale accordingly base on the scale ratio we defined. I want the text larger so the text size for <p>
is --font-size: var(--fs-copy-med)
which is 1.25rem
. This is important to me because enlarging the text size for copy to 20px
is way more comfortable to read on phones.
/* base font size settings */
:root {
--font-size: 1rem;
--font-weight: 400;
--line-height: 1.563;
}
I figured if I set the text size on body isn’t 1rem
it’ll mess up the em
calculation for width, so font-size
for <body>
stays at 1rem
. I’m aware of the inheritance issue. So, I intentionally targeted these elements specifically. The reason for not using the universal selector * {...}
is because I want to apply the font size to the elements that I’ll be using. I hand-picked each one of them.
/* base font settings will apply as below */
html, body, header, nav, main, article, section, aside, footer,
h1, h2, h3, h4,
ul, ol, li, dl, dt, dd,
p, pre, div, figure, figcaption, blockquote, cite,
table, th, td, textarea,
a, span, code, time, ruby, rt, em, mark, kbd, q, sub, sup, b, strong, small {
font-size: var(--font-size);
font-weight: var(--font-weight);
line-height: var(--line-height);
}
Type Scale is a tool for calculating font scale. I’m picking ratio 1.25, the Major Third because it looks best for the design. Based on the scale ratio, I defined a set of global tokens for headings and copy text. Note that the 22px
and 18px
are extra sizes. All font-size
s are set to the unit rem
. As I understand correctly, rem
unit is only relative to the font-size
in :root
. That being said, we can scale all variables at once using @media
.
/* global tokens */
:root {
--fs-headline-lrg: 3.052rem; /* 48.83px */
--fs-headline-h1: 2.441rem; /* 39.06px */
--fs-headline-h2: 1.953rem; /* 31.25px */
--fs-headline-h3: 1.563rem; /* 25px */
--fs-headline-h4: 1.375rem; /* 22px + */
--fs-copy-lrg: 1.5rem; /* 24px + */
--fs-copy-med: 1.25rem; /* 20px */
--fs-copy-sml: 1.125rem; /* 18px + */
--fs-base: 1rem;
}
Line Height & Line Length
The line-height
is now set to 1.563
which is also based on 1.25 ratio. And for that, does it make the spacing between headings and paragraphs more comfortable to read? This is an answer I’d like to find out, maybe time will tell. If I have the time I’ll probably adjust the scale to 1.5 for text sizes for larger viewport.
By using max-width
the content width is now limited to 48em
where the Type Scale also is applied to the page that based on the global tokens defined in :root
. All text sizes will scale if the viewport width exceeds 48em
. The line length limited to 768px
is more optimal to read if the screen gets too wide. I did try using ch
for text block width but to be honest I don’t see there’s much of a difference as we can adjust line length through whatever unit was set. All font-size
are now fixed values. I might want to play around a bit more on Fluid Type Scale using calc()
but let’s call it a day, for now.
Alignment & Spacing
The hanging-punctuation
property isn’t support in most browsers. However, I still want to apply it in a way that not limited to quote marks. For instance, bullet points for <ul>
. So I created my own version of it, well, sort of. All text aligned to left and setting a negative margin-left
for elements like <figure>
or <pre>
and then apply padding
to it. So, no matter it’s a <div>
or a <p>
, all text content will be aligned in a straight vertical line to the left whatever their font-size
or wherever they are nested in. Inline <code>
doesn’t count. Update: I’m afraid it’ll only applies to smaller viewport under 48em
wide. It is because the gutter in-between two columns. However, bullet points or quote marks will hang outside of main column. I dislike text being aligned in the center, secretly hating the property text-align: center
.
For spacing between headings and paragraphs, a set of global values were defined using Custom Properties. There’ll be a margin-top
for headings which will apply when there’s an element before it by using the selector for sibling * + h2
. As far as I know, the em
unit is relative to its parent font-size
and it will scale accordingly, which is nice. The value of margin-top
that set to the headings is greater than its previous element margin-bottom
, so the margin collapse shouldn’t be an issue.
/* three values for global spacing */
:root {
--spacing-lrg: 1.953em;
--spacing-med: 1.25em;
--spacing-sml: .8em;
}
/* margin-top for h2 to h4 */
* + h2,
* + h3,
* + h4 {
margin-top: var(--spacing-med);
}
For cross alignment, aligning text horizontally across columns is a topic that I not yet have the ability nor knowledge to even try to implement in web. When I was doing print design, my early experience on desktop publishing was using Adobe PageMaker then shift to InDesign. I used InDesign extensively during my study in Visual Communication because of its ability to create grids, columns and templates. It was also the moment when I learnt how to set up a baseline grid for a document. I’ll keep researching on it and maybe, just maybe, someday I’m able to make it happens.
CJK type mixed with Latin text
The font-family
for latin-based languages is using System Font Stack suggested by Bootstrap’s Reboot. It reduces page load time as it does not require loading any extra web fonts. Easy to implement, safe to use and also brings consistency for the design, especially on Apple’s devices. However, when you’re writing a post and English isn’t your first language, we often use East Asia text mixed in with English, which is Chinese and Japanese in this case. CJK stands for Chinese, Japanese and Korean.
Styling Japanese Text
Testing CJK type font-family
. Still researching on the system font stack for CJ fonts. Also, trying the <ruby>
element. It is because even if the majority of the content is in English and you might want to mention a film or anime title in a blog post from time to time. It’ll happen, so here you go— A 2019 Japanese Anime film: Weathering with You, 天気の子 by director Makoto Shinkai 新海 誠.
The <ruby>
contain two child elements <rt>
and <rp>
. Using display: inline-flex
to adjust the <rt>
position. Setting --font-size: calc(1em - 50%)
on <rt>
, the 1em
which is equivalent to the content text size and then scale it down by -50%
. Also, the --line-height: 0
is to make sure <ruby>
for Chinese characters 漢字 won’t affect the same row of text where it’s injected. Update: After some research and testing seems like using two separate <ruby>
for first name and last name or each annotation works best.
<!-- ruby annotation element -->
<p>
Hina Amano
<ruby lang="ja">
天野<rp>(</rp><rt>あまの</rt><rp>)</rp>
陽菜<rp>(</rp><rt>ひな</rt><rp>)</rp>
</ruby>
</p>
<!--
that’s a lot of code (=’X’=).
for the <rt> position it appears not consistent on browsers
-->
A high school boy Hodaka Morishima 森嶋帆高 who runs away from his rural home to Tokyo and befriends an orphan girl Hina Amano 天野陽菜 nicknamed the 100% Sunshine Girl, 晴れ女 who has the power to stop the rain and clear the skies with just a prayer.
/* styles only applies to ruby with lang attribute ja */
:where(ruby:lang(ja)) {
font-family: var(--font-jp-gothic);
font-style: normal;
}
The font style only applies to the <ruby>
element with lang="ja"
attribute using :where()
pseudo-class. The default language for the document is <html lang="en">
while declaring a language to an element that contain Japanese text will be <ruby lang="ja">
. I think it does the job nicely, at least to my testing. For the font-style: normal
, I added it in intentionally is because Chinese and Japanese don’t have italic or oblique styles at all. Which is added just to in case of any font styles being applied.
I love Japanese text written in Mincho (serif). Even though I admit that Gothic (sans-serif) is easier to read on screen. But it’s just beautiful. The font for :lang(ja)
will be set in Gothic. I created a class .jp-mincho
just for Mincho font stack. As we need to specify language other than content default by lang
attribute anyways, so it won’t hurt to have an extra class. I don’t think it’ll need the :lang(ja-JP)
region code for Japan, so I’m gonna skip that. The specified language doesn’t necessarily need to relate to the region. After a lot of research here’s the version I’m now using:
/* JP Gothic */
--font-jp-gothic: "ヒラギノ角ゴ ProN", "Hiragino Kaku Gothic ProN", "Hiragino Sans", "游ゴシック", "游ゴシック体", YuGothic , "Yu Gothic", "メイリオ", Meiryo, "MS ゴシック", "MS Gothic", sans-serif;
/* JP Mincho */
--font-jp-mincho: "ヒラギノ明朝 ProN", "Hiragino Mincho ProN", "游明朝", "游明朝体", YuMincho, "Yu Mincho", "MS 明朝", "MS Mincho", serif;
That’s quite a lot going on for styling Japanese text. To be honest, it seems to me a lot of effort went into it but having very little effect. Update: Font declaration mostly based on this article by Hayataki Masaharu Senpai, and I refreshed it a little bit which are more to my taste. Also, the <rp>
fallback is quite troublesome to add in HTML.
Traditional Chinese Font Stack
I use Traditional Chinese(TC) language since I was born. Personally, I think the traditional style is considered to be one of the most beautiful and sophisticated written language amongst other languages in the world. You might think I’m exaggerating, but no. You’ll agree if you know the language.
千言萬語 盡在不言中
Every word has its history and wisdom which coincides with the forms and strokes. The complexity of the characters is why it’s so fascinating. When words and phrases come together it creates poetic and aesthetically beautiful meaning, especially when it’s written in calligraphy. It’s a very complicated writing system that I can barely scratch the surface of it.
/* CJK font size and style */
:where(:lang(ja), :lang(zh-HK)) {
--font-size: calc(1em - 6%);
font-style: normal;
}
/* TC font stack */
--font-hk: var(--font-mix), "PingFang HK", "SF Pro HK", "Hiragino Sans CNS", "LiHei Pro Medium", "微軟正黑體", "Microsoft JhengHei", "Microsoft JhengHei UI", sans-serif;
CJK type is larger than Latin text even if they’re set to the same rem
. So I make it slightly smaller -6%
. There isn’t any surprise in the font stack, at all. Targeting both macOS and Windows system font. When it is used in a text block, a language attribute will be added. For example, a <span>
will be added to wrap the Chinese content with the lang="zh-HK"
attribute. I purposefully added in the region code for labeling it’s in Traditional Chinese as well as to make it clear where it’s from—Hong Kong.
Bilingual Font Stack
The below example shows Japanese text using the suggested font stack. It’s easy to style them separately. For instance, a <ruby>
or some simple words, you could wrap it in a <span>
, no problem. However, the tricky part is that when a sentence written in Japanese and some English wordings mix in, they are considered as part of the language being spoken, as I understand correctly. To make this clear, a text block <p>
contains text which are not entirely written in Japanese characters but with Latin text within it. So, here’s the thing, the font-family
declaration needs font stack var(--font-mix)
for Latin characters. As far as I know, Chinese and Japanese font contains Latin characters in the font file. Setting English font before Japanese in the declaration order will let Latin text to display using English font instead of the latter. The same rule applies to TC font stack.
Amano Hina 天野陽菜
Amano Hina 天野陽菜
One last thing, if you’re going to implement Chinese web font, do not include FangSong 仿宋 as body text. Don’t ever do that. It is because the typeface aren’t meant for web use but for print. Basically it’s illegible at smaller viewport. For web font, Heiti 黑體 will be your best bet. On macOS, Simplified Chinese Sans-serif: "PingFang SC"
, "Hiragino Sans GB"
or STHeiti
and Serif: Songti
.
That’s what I ended up for styling CJK text. I’m not sure am I doing it correctly and I don’t intend the post to be a tutorial or guidelines. This is my attempt to implement font stack bilingually. If you have interest in non-Latin text CSS support in the future, read more on this article by Richard Ishida. Update: The Mincho font stack seems not in effect in Safari if it has var(--font-mix)
. I’ll get into it later.
Update: A piece about CSS for East Asian text by Hui Jing Chen. Geez, I wish I could have seen this earlier…You can learn so much from her article. I’m now gets even more embarrassed of myself. Sigh…
Page Structure
Again, I try to make everything as simple as possible. There won’t be an Update: This is not true anymore, extra <div>
when it’s not needed.<div>
has to be added for grid layout. And yes, I feel guilty by adding them. I revisited W3C WAI for semantic Content Structure. Understanding each of the HTML elements, to pick and use them semantically then apply CSS.
HTML Structure
The html
structure is fairly basic. It’s pretty standard by using the most generic elements. Such as <header>
, <footer>
, <main>
, <article>
and the rest are just normal stuff.
<!-- blog post structure -->
<main class="page">
<article class="post">
<header class="post--header">
<h1>...</h1>
</header><!-- / .post--header -->
<div class="post--body">
<p class="lead">...</p>
<h2>...</h2>
<p>...</p>
</div><!-- / .post--body -->
<footer class="post--footer">
...
</footer><!-- / .post--footer -->
</article><!-- / .post -->
</main>
I created the list below as a reminder. It’s time to relearn all that basics again. This is fun, isn’t it?
HTML Elements
- Content Sectioning
<header>
<nav>
<main>
<article>
<section>
<aside>
<footer>
- Headings
<h1>
<h2>
<h3>
<h4>
- Text Content
<p>
<pre>
<hr>
<figure>
<figcaption>
<blockquote>
<cite>
- Lists
<ul>
<ol>
<li>
<dl>
<dt>
<dd>
- Inline Text
<a>
<span>
<code>
<time>
<ruby>
<mark>
<ruby>
<rt>
<q>
<sup>
<sub>
<b>
<strong>
<small>
- Others
<picture>
<table>
<caption>
<input>
<textarea>
<details>
<summary>
<select>
Page Layout
The page layout is wrapped in <main>
and using the vw
unit as padding
for the entire page. It works super cool as you don’t need to do the math yourself but instead, let the browser do the calculation. For the time being, this is a single column website because there aren’t enough content. Update: the layout is now set in two columns. Different units will be used: vw
for page layout, rem
for font-size
, em
for width
and spacing, px
for border
.
Grids & Columns
Before the whole Responsive Design was invented, the web was dominated with fixed width websites. The 960 Grid System has been a trend to follow if you’re into web design. As I recall, even after the iPhone 3G came out in 2008 it still was very popular. Those were the good ol’ days because I was lucky enough to be one of the designers who had worked on some web projects using 960GS, the Holy Grail. I admit that when I landed the role as a web designer, I was one of the guy who coded quite a numbers of webpages layout by nesting <table>
. And after that, I learnt what a <div>
is and started to use float
to do layout. We used to add a class .clearfix
to clear float. I think I’m fortunate to witness the rising of Responsive Layout for which it brings web design into a new era. That’s already been a decade. Time flies, but it seems so recent to me.
At the times, I read a lot of articles on using Grid System to design Adaptive Layout and Fluid Layout. Some people had written something very insightful, they were so ahead of their time: The Incredible Em & Elastic Layouts with CSS by Jon Tan. Mark Bolton’s Five Simple Steps Series was one of my favorite. I was very new to web design when I first read it and can’t even tell what’s the difference between an id or class. I reread it again recently and I’m now trying to recreate the 960 Grid using display: grid
for nostalgic reason.
For the grid layout, basically there’re two columns: .col--side
and .col--main
and the widths are 16em
and 48em
wide, respectively. Simple enough. The left side column is for subtitles and the main column of course is for content. As subtitles has relation to the headings in main column but they are being placed in different area. The horizontal line at the top of the columns is to create visual connection between them even they are separated by gutter, in CSS gap
. When the layout is view on mobile the subtitles will stack on top of the headings. I hope this treatment can still remain as semantically correct even those div
s were added. Still figuring out how display: grid
works and testing, please bear with me.
CSS Reset & Classes
I’ve seen people talking about modern CSS reset for quite a while. But Eric Meyer’s CSS Reset has being used on many websites for so long. It maybe too extreme by today’s standard but it was effective. I read some more articles and decided to mix and match my own version. I’d call it Fusion™. Basically, what I did was reduced the code without adding anything new to it. By targeting the universal selector *
then apply margin: 0
, padding: 0
and of course box-sizing: border-box
. I also added in text-size-adjust
for the CSS reset. I did almost nothing, but still, worth investigating on how it works. Also,
I also try to keep to a minimal level of classes used in the document for styling. Class names are quite hard to think of though. I’m now using a not so sure but sort of BEM method, for which I don’t like underscore, instead, I decided to go with double hyphens — two dashes: .page {...}
, .page--header {...}
for class names. It seems to me it looks better while editing HTML.
Design Inspiration
I drew inspiration from John Doe’s Page heavily. I admit that it’s a clever idea of using :target
and I love it. It took something so simple then turned into a unique and beautifully done website. I still remembers back in the day when Yahoo! GeoCities was a thing. Believe it or not, I once had a website on GeoCities as well, because it was free to have one. That’s almost 20 or more years ago. Damn, I’m old.
I was amazed by John Kane’s book A type primer when I was studying Visual Communication. This book covers the fundamentals of typography and it teaches me a lots that I still find useful today. That was something like 16 years ago. It also was the first book that introduced me to classifying typefaces, type treatment, text alignment and grid systems. I insist to type set “flush left, ragged right” and making sure all text aligned to the left axis even when I’m doing web design. If anyone dares to set “justified” to a text block, I think you probably should call the police because it’s barely legal. We’re using the term “tracking” or “kerning” today to describe spacing adjustment between letters. But originally kerning means to reduce the space of it whereas “letterspacing” means increasing. I still remembers what it had taught me.
For design direction, I went with bold type and thick lines approach without any rounded corners. I took my time, starting to apply some touchups for the design and hopefully it looks more refined. Let’s bake it a little bit longer this time, we’ll see.
Improvements
It’s a completely static website. There’s no backend, no CMS, no JavaScript, no static site generator, no search, no archive, no sorting, no tags feature, not even pagination, no nothing. I hard-coded the whole thing using HTML and PHP. You may laugh all you want. But one thing, every line of HTML and CSS was written by me and that’s that. I kind of like it because it’s Extra Ordinary.
Everything I’ve done here was the essentials of constructing a web page. I hope I did my research enough and reflected it in the code. I might consider turning this into an PWA. Also, some of the techniques I’d like to try:
- Micro Typography — See if I can adjust the text sizes and spacing to be more precise and refined
- Baseline Grid — If you think vertical alignment is hard, aligning text horizontally across columns is even harder
- Self-host Web fonts — Been thinking to try out Atkinson Hyperlegible
- Web Accessibility — Read more about web standards and learn how to implement them correctly
- Favicon, SVG icons — I’m now in search for a SVG icons set. If I have the time, I’ll make a logotype for the site: Fury. Besides, it does not have a favicon yet. Of course it’ll be an SVG
Summing Up
The development of this site is a ongoing progress. I’ll keep experimenting with things. It’s also a slow learning progress of pretty much everything that I thought I know. I’m not satisfied with the layout but let’s settle on it for a while. I’m going to clean up the CSS and HTML structure as well as actually start writing things.
It took me a month to be able to get here. If there is a one-in-a-billion chance of anyone actually reading this post, please do let me know! I would be very glad to hear what you think. I apologize for my poorly written English if you suffer from reading. See you next time.
Footnotes
- Web Design is 95% Typography (Oct 2006) by Oliver Reichenstein ↩︎
- Typographic scale basics (Nov 2021) by 30 seconds of code ↩︎
- CSS Custom Properties - 12 Days of Web (Dec 2021) by Stephanie Eckles ↩︎
- The Big Gotcha With Custom Properties (Aug 2021) by Chris Coyier ↩︎
- Type Scale by Jeremy Church ↩︎
- A Strategy Guide To CSS Custom Properties (May 2018) by Michael Riethmuller ↩︎
- Generating "font-size" CSS Rules and Creating a Fluid Type Scale (Jun 2021) by Stephanie Eckles ↩︎
- The Most Comprehensive Guide to Web Typography in Japanese (Dec 2015) by Hayataki Masaharu ↩︎
- Declaring language in HTML (Jun 2021) by Richard Ishida, W3C ↩︎
- CSS and International Text (Jul 2016) by Richard Ishida, W3C ↩︎
- CSS for internationalisation (Apr 2020) by Hui Jing Chen ↩︎
- Your CSS reset needs text-size-adjust (probably) (Jan 2022) by Kilian Valkhof ↩︎
- John Doe’s Page on Github by @cadars ↩︎