├── eyeglass-exports.js ├── .gitignore ├── sache.json ├── bower.json ├── package.json ├── .gitattributes ├── readme.md └── sass └── index.scss /eyeglass-exports.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | 3 | module.exports = function(eyeglass, sass) { 4 | return { 5 | sassDir: path.join(__dirname, "sass") 6 | } 7 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## General 2 | .cvs 3 | .htaccess 4 | .svn 5 | *.bak 6 | *.log 7 | *.swp 8 | 9 | ## Windows 10 | Desktop.ini 11 | Thumbs.db 12 | 13 | ## Mac 14 | .DS_Store 15 | 16 | ## Development 17 | .sass-cache 18 | bower_components 19 | node_modules 20 | 21 | ## Project specific 22 | -------------------------------------------------------------------------------- /sache.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sass-font-stacker", 3 | "description": "A Sass micro-library for working with pre-defined font stacks", 4 | "tags": ["font", "fonts", "type", "typography", "chinese", "cjw"], 5 | "website": "https://www.github.com/synapticism/sass-font-stacker", 6 | "docs": "https://www.github.com/synapticism/sass-font-stacker" 7 | } -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sass-font-stacker", 3 | "homepage": "https://github.com/synapticism/sass-font-stacker", 4 | "authors": [ 5 | { 6 | "name": "Alexander Synaptic", 7 | "email": "alexander@synapticism.com", 8 | "homepage": "http://synapticism.com" 9 | } 10 | ], 11 | "main": "sass/index.scss", 12 | "keywords": [ 13 | "sass", 14 | "scss", 15 | "font", 16 | "fonts", 17 | "fontstack", 18 | "fontstacks", 19 | "type", 20 | "typography", 21 | "chinese", 22 | "cjw" 23 | ], 24 | "license": "MIT/GPLv3", 25 | "ignore": [ 26 | "node_modules", 27 | "bower_components", 28 | "test", 29 | "tests" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sass-font-stacker", 3 | "version": "0.4.3", 4 | "description": "A Sass micro-library for working with pre-defined font stacks", 5 | "homepage": "https://www.github.com/synapticism/sass-font-stacker", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://www.github.com/synapticism/sass-font-stacker.git" 9 | }, 10 | "keywords": [ 11 | "sass", 12 | "scss", 13 | "font", 14 | "fonts", 15 | "fontstack", 16 | "fontstacks", 17 | "type", 18 | "typography", 19 | "chinese", 20 | "cjw", 21 | "eyeglass-module" 22 | ], 23 | "author": "Alexander Synaptic ", 24 | "license": "GPL-3.0", 25 | "main": "sass/index.scss", 26 | "eyeglass": { 27 | "needs": "^0.7.1", 28 | "exports": "eyeglass-exports.js" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # .gitattributes adapted from https://github.com/Danimoth/gitattributes 2 | 3 | # Auto detect text files and perform LF normalization via http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/ 4 | * text=auto 5 | 6 | # These files are text and should be normalized (Convert crlf => lf) 7 | *.php text 8 | *.css text 9 | *.js text 10 | *.htm text 11 | *.html text 12 | *.xml text 13 | *.txt text 14 | *.ini text 15 | *.inc text 16 | .htaccess text 17 | 18 | # Documents 19 | *.doc diff=astextplain 20 | *.DOC diff=astextplain 21 | *.docx diff=astextplain 22 | *.DOCX diff=astextplain 23 | *.dot diff=astextplain 24 | *.DOT diff=astextplain 25 | *.pdf diff=astextplain 26 | *.PDF diff=astextplain 27 | *.rtf diff=astextplain 28 | *.RTF diff=astextplain 29 | 30 | # These files are binary and should be left untouched 31 | # (binary is a macro for -text -diff) 32 | *.png binary 33 | *.jpg binary 34 | *.jpeg binary 35 | *.gif binary 36 | *.ico binary 37 | *.mov binary 38 | *.mp4 binary 39 | *.mp3 binary 40 | *.flv binary 41 | *.fla binary 42 | *.swf binary 43 | *.gz binary 44 | *.zip binary 45 | *.7z binary 46 | *.ttf binary 47 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # SASS FONT STACKER 2 | 3 | This Sass micro-library provides a simple way to work with a pre-defined set of presumably web-safe font stacks. Two functions and a single mixin provide a bit of syntactic sugar to make it easier to prepend any of the existing fonts stacks with an arbitrary number of fonts. 4 | 5 | What this library *won't* do is output an `@import` declaration for web fonts. For that you'll want to turn to something like [Sass Web Fonts](https://github.com/penman/Sass-Web-Fonts) but be warned: [CSS imports are an anti-pattern](http://www.stevesouders.com/blog/2009/04/09/dont-use-import/), good for the developer and bad for performance. 6 | 7 | [Read the announcement on my blog](http://synapticism.com/dev/a-sass-micro-library-for-web-safe-font-stacks/). 8 | 9 | 10 | 11 | ## Installation 12 | 13 | Download/clone this repo or install with either npm (`npm install sass-font-stacker --save-dev`) or Bower (`bower install sass-font-stacker -D`). Then simply `@import sass-font-stacker` somewhere in your code (as long as this project is included in your load paths anyway). 14 | 15 | This project has no dependencies. Requirements: Sass 3.3+. 16 | 17 | 18 | 19 | ## Usage 20 | 21 | This library defines a mixin and a utility function that accept an arbitrary list of fonts. The last items in the list (or the only item, as the case may be) *must* be the name of one of the font stacks included in the `$k-font-stacks` map variable (browse source for a full list). 22 | 23 | ```scss 24 | @mixin k-font-family($fonts...) 25 | @function k-font-stack($fonts...) 26 | ``` 27 | 28 | An example with two leading fonts: 29 | 30 | ```scss 31 | @import "sass-font-stacker/font-stacker"; 32 | body { 33 | @include k-font-family("PT Serif", "PT Serif Pro", georgia); 34 | } 35 | ``` 36 | 37 | This will render: 38 | 39 | ```css 40 | body { 41 | font-family: "PT Serif", "PT Serif Pro", Georgia, "Palatino Linotype", Palatino, "URW Palladio L", "Book Antiqua", "Times New Roman", serif; 42 | } 43 | ``` 44 | 45 | You can also get a little closer to the base metal: 46 | 47 | ```scss 48 | body { 49 | font-family: k-font-stack(georgia); 50 | } 51 | ``` 52 | 53 | Which will output: 54 | 55 | ```css 56 | body { 57 | font-family: Georgia, "Palatino Linotype", Palatino, "URW Palladio L", "Book Antiqua", "Times New Roman", serif; 58 | } 59 | ``` 60 | 61 | Note that the only *required* argument is the *last* argument which should be one of the pre-defined font stacks. This way you can prepend an arbitrary number of web fonts using syntax that doesn't stray too far from what you'd be doing otherwise. If something goes horribly wrong there is a backup defined by `$k-font-stack-default` which is currently set to `courier` (so it'll be readily apparent that you've requested a stack that could not be found). 62 | 63 | The second utility function returns a font stack without the generic term (e.g. `sans-serif`, `monospace`, etc.) at the end. The purpose of this is to allow for font stacks to be welded together as needed (with an eye toward international font sets). For instance: 64 | 65 | ```scss 66 | body { 67 | font-family: k-font-stack("Noto Sans", k-font-stack-trim(helvetica), k-font-stack-trim(zh-heiti-tc), sans-serif); 68 | } 69 | ``` 70 | 71 | This will return a declaration that includes Chinese fonts at the end. 72 | 73 | 74 | 75 | ## Font stacks 76 | 77 | The font stacks themselves result from a combination of research, experience, guesswork, and idle whim. I don't pretend to be an expert in these matters but then again, who is? Most of the articles written about web-safe font stacks are five years old and usage data is lousy and poorly sourced. I have at least gone to the trouble of sprinkling most font stacks with a few free and open source alternatives so as to not ignore Linux users the way some designers do. 78 | 79 | At any rate, you aren't locked into using what I have compiled here. Want to define your own font stacks on a per-project basis? Add to the `$k-font-stacks` global: 80 | 81 | ```scss 82 | $k-font-stacks: map-merge($k-font-stacks, ( 83 | helvetica-only: (Helvetica, sans-serif) 84 | )); 85 | ``` 86 | 87 | Sane pull requests are also welcome! 88 | 89 | 90 | 91 | ## Chinese font stacks 92 | 93 | This package also includes Chinese character support, both traditional and simplified. For more about using these fonts check out [Kendra Schaefer's Chinese font guide](http://www.kendraschaefer.com/2012/06/chinese-standard-web-fonts-the-ultimate-guide-to-css-font-family-declarations-for-web-design-in-simplified-chinese/), [the complete beginner's guide to Chinese fonts](http://webdesign.tutsplus.com/articles/the-complete-beginners-guide-to-chinese-fonts--cms-23444), and [Yale's Chinese font reference](http://www.yale.edu/chinesemac/pages/fonts.html). For a native Chinese approach check out [Zeno Zeng's fonts.css](https://github.com/zenozeng/fonts.css). 94 | 95 | 96 | 97 | ## Links 98 | 99 | * [Font Family Reunion](http://fontfamily.io/): compatibility tables for default system fonts. 100 | * [ffffallback](http://ffffallback.com/): a bookmarklet to help choose fallback fonts. 101 | * [The New System Font Stack](https://bitsofco.de/the-new-system-font-stack/): a little more about where the `system-sans` stack came from in 2016. 102 | 103 | 104 | 105 | ## Credits 106 | 107 | Many of these font stacks are modifications of font stacks I've collected over the years. Many of my sources are no longer online. Among those that are: [this post by Michael Tuck](http://www.sitepoint.com/eight-definitive-font-stacks/), [this post on A Way Back](http://www.awayback.com/revised-font-stack/), [this post on Mighty Meta](http://www.mightymeta.co.uk/web-safe-fonts-cheat-sheet-v-3-with-font-face-fonts-and-os-breakdown/), some tips about Futura and Century Gothic on [Intavent](http://intavant.com/), a cursory inspection of [Dan's Tools](http://www.cssfontstack.com/), and [the Wayback Machine](https://webcache.googleusercontent.com/search?q=cache:http://www.visibone.com/font/FontResults.html&gws_rd=cr&ei=CazNVMvABsT38QWgjYD4CQ). 108 | 109 | 110 | 111 | ## License 112 | 113 | MIT/GPLv3. 114 | -------------------------------------------------------------------------------- /sass/index.scss: -------------------------------------------------------------------------------- 1 | // ==== FONT STACKER ==== // 2 | 3 | // Set a default font stack; if you see monospaced type something probably went wrong ;) 4 | $k-font-stack-default: courier; 5 | 6 | // Font stack definitions 7 | $k-font-stacks: ( 8 | 9 | // == SERIF == // 10 | 11 | baskerville: (Baskerville, "Baskerville Old Face", Utopia, "Hoefler Text", "Times New Roman", "DejaVu Serif", "Liberation Serif", Tinos, serif), 12 | big-caslon: ("Big Caslon", "Book Antiqua", Bookman, Palatino, "Palatino Linotype", "Palatino LT STD", "URW Palladio L", "DejaVu Serif", Georgia, serif), 13 | bodini-mt: ("Bodoni MT", Didot, "Didot LT STD", "Times New Roman", "DejaVu Serif", "Liberation Serif", Tinos, serif), 14 | book-antiqua: ("Book Antiqua", Palatino, "Palatino Linotype", "Palatino LT STD", "URW Palladio L", "DejaVu Serif", Georgia, serif), 15 | calisto-mt: ("Calisto MT", "Bookman Old Style", Bookman, "Goudy Old Style", "Hoefler Text", "Bitstream Charter", Charter, "DejaVu Serif", Georgia, serif), 16 | cambria: (Cambria, "Hoefler Text", Utopia, "DejaVu Serif", "Liberation Serif", Georgia, serif), 17 | constantia: (Constantia, "Lucida Bright", "Lucida Serif", Lucida, "DejaVu Serif", "Liberation Serif", Georgia, serif), 18 | didot: (Didot, "Didot LT STD", "Times New Roman", "DejaVu Serif", "Liberation Serif", Tinos, serif), 19 | garamond: (Garamond, Garamond-Normal, Baskerville, "Baskerville Old Face", Utopia, "Times New Roman", "DejaVu Serif", "Liberation Serif", serif), 20 | georgia: (Georgia, Palatino, "Palatino Linotype", "Palatino LT STD", "URW Palladio L", "Book Antiqua", "DejaVu Serif", serif), 21 | goudy: ("Goudy Old Style", "Hoefler Text", "Times New Roman", "DejaVu Serif", "Liberation Serif", Tinos, serif), 22 | hoefler: ("Hoefler Text", Baskerville, "Baskerville Old Face", "Times New Roman", "DejaVu Serif", "Liberation Serif", Tinos, serif), 23 | lucida-bright: ("Lucida Bright", Lucidabright, "Lucida Serif", Lucida, "DejaVu Serif", "Liberation Serif", Tinos, serif), 24 | palatino: (Palatino, "Palatino Linotype", "Palatino LT STD", "URW Palladio L", "Book Antiqua", "DejaVu Serif", Georgia, serif), 25 | times: ("Times New Roman", TimesNewRoman, "DejaVu Serif", "Liberation Serif", Tinos, Times, serif), 26 | 27 | 28 | 29 | // == SANS-SERIF == // 30 | 31 | arial: (Arial, "Helvetica Neue", Helvetica, "Nimbus Sans L", "Liberation Sans", Arimo, sans-serif), 32 | calibri: (Calibri, Candara, "Gill Sans", "Gill Sans MT", "DejaVu Sans", Verdana, Geneva, sans-serif), 33 | candara: (Candara, Calibri, "Gill Sans", "Gill Sans MT", "DejaVu Sans", Verdana, Geneva, sans-serif), 34 | century: ("Century Gothic", "Apple Gothic", AppleGothic, "URW Gothic L", Avantgarde, "DejaVu Sans", Tahoma, sans-serif), 35 | corbel: (Corbel, "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", "DejaVu Sans", Verdana, Geneva, sans-serif), 36 | frutiger: (Frutiger, "Frutiger Linotype", Calibri, "Gill Sans", "Gill Sans MT", "DejaVu Sans", Verdana, Geneva, sans-serif), 37 | futura: (Futura, Futura-Medium, "Futura Medium", Avantgarde, "Century Gothic", "Apple Gothic", AppleGothic, "URW Gothic L", "DejaVu Sans", Tahoma, sans-serif), 38 | geneva: (Geneva, Verdana, "DejaVu Sans", sans-serif), 39 | gill-sans: ("Gill Sans", "Gill Sans MT", Calibri, "DejaVu Sans", Verdana, Geneva, sans-serif), 40 | helvetica: ("Helvetica Neue", Helvetica, Arial, "Nimbus Sans L", "Liberation Sans", Arimo, sans-serif), 41 | helvetica-light: ("HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Nimbus Sans L", "Liberation Sans", Arimo, sans-serif), 42 | lucida-grande: ("Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", "DejaVu Sans", Verdana, Geneva, sans-serif), 43 | myriad: ("Myriad Web", "Myriad Pro", Myriad, "Gill Sans", "Gill Sans MT", "DejaVu Sans", Verdana, Geneva, sans-serif), 44 | optima: (Optima, Segoe, "Segoe UI", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", "DejaVu Sans", Verdana, Geneva, sans-serif), 45 | segoe: (Segoe, "Segoe UI", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", "DejaVu Sans", Verdana, Geneva, sans-serif), 46 | system-sans: (-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif), 47 | tahoma: (Tahoma, "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", "DejaVu Sans", Verdana, Geneva, sans-serif), 48 | trebuchet: ("Trebuchet MS", Futura, "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", "DejaVu Sans", Tahoma, sans-serif), 49 | verdana: (Verdana, Geneva, "DejaVu Sans", sans-serif), 50 | ubuntu: (Ubuntu, "Myriad Web", "Myriad Pro", Myriad, "Gill Sans", "Gill Sans MT", "DejaVu Sans", Verdana, Geneva, sans-serif), 51 | 52 | 53 | 54 | // == DISPLAY == // 55 | 56 | comic-sans: ("Comic Neue", "Comic Sans MS", "Comic Sans", Chalkboard, "ChalkboardSE-Regular", "Marker Felt", Purisa, "URW Chancery L", cursive), // http://www.mcdruid.co.uk/content/cursive-font-stack :) 57 | impact: (Impact, Haettenschweiler, "Franklin Gothic Bold", Charcoal, "Helvetica Inserat", "Bitstream Vera Sans Bold", "Arial Black", sans-serif), 58 | papyrus: (Papyrus, "ITC Papyrus", fantasy), // :D 59 | 60 | 61 | 62 | // == MONOSPACE == // 63 | 64 | andale: ("Andale Mono WT", "Andale Mono", Menlo, "Lucida Console", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", monospace), 65 | consolas: (Consolas, "Andale Mono WT", "Andale Mono", Menlo, "Lucida Console", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", monospace), 66 | courier: ("Courier New", Courier, "Courier 10 Pitch", "Liberation Mono", "Nimbus Mono L", "Cousine", monospace), 67 | menlo: (Menlo, Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", monospace), 68 | typewriter: ("Lucida Sans Typewriter", "Lucida Typewriter", "Courier New", Courier, "Courier 10 Pitch", "Liberation Mono", "Nimbus Mono L", "Cousine", monospace), 69 | ubuntu-mono: ("Ubuntu Mono", Monaco, Consolas, "Lucida Console", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", monospace), 70 | 71 | 72 | 73 | // == CHINESE == // 74 | 75 | // Songti: similar to serif; think Times New Roman 76 | zh-songti-sc: ("Songti SC", STSong, 华文宋体, 宋体, SimSun, 新宋体, NSimSun, "AR PL New Sung", "AR PL SungtiL GB", serif), 77 | zh-songti-tc: ("LiSong Pro", "Apple LiSung", 新細明體, PMingLiU, MingLiU, "AR PL Mingti2L", "TW\-Sung", serif), 78 | 79 | // Heiti: similar to sans-serif; think Helvetica/Arial 80 | zh-heiti-sc: ("Heiti SC", "Microsoft YaHei New", "Microsoft Yahei", 微软雅黑, SimHei, 黑体, "STHeiti Light", STXihei, 华文细黑, STHeiti, 华文黑体, "WenQuanYi Zen Hei", sans-serif), 81 | zh-heiti-tc: ("Heiti TC", "Microsoft JhengHei", 微軟正黑體, sans-serif), 82 | 83 | // Kaiti: a regular brush script 84 | zh-kaiti-sc: ("Kaiti SC", KaiTi, 楷体, STKaiti, 华文楷体, Kai, "AR PL UKai CN", serif), 85 | zh-kaiti-tc: ("BiauKai", "DFKai-SB", "AR PL KaitiM", "AR PL KaitiM GB", "AR PL UKai HK", "AR PL UKai TW", "TW\-Kai", serif), 86 | 87 | // Fangsongti: stylized brush script; a fusion of kaiti and songti styles; only available for simplified Chinese insofar as I can tell 88 | zh-fangsong-sc: (FangSong, "Fang Song", 仿宋, STFangSong, 华文仿宋, serif), 89 | 90 | 91 | 92 | // == BASICS == // 93 | 94 | // For use with `k-font-stack-trim`) 95 | cursive: (cursive), 96 | fantasy: (fantasy), 97 | monospace: (monospace), 98 | sans-serif: (sans-serif), 99 | serif: (serif) 100 | ); 101 | 102 | 103 | 104 | // Font stacker function; accepts an arbitrary list of font names (including none at all); requires the name of a valid font stack from the list above as the last or only argument 105 | @function k-font-stack($fonts...) { 106 | 107 | // Assume the target stack is the last value in the arglist; break it off into a string 108 | $stack: nth($fonts, -1); 109 | 110 | // Remove the last value from the arglist to avoid duplication or create an empty list as needed 111 | @if length($fonts) > 1 { 112 | $fonts: set-nth($fonts, -1, null); 113 | } @else { 114 | $fonts: (); 115 | } 116 | 117 | // Check to see if the stack exists and return the combined list; fallback to the default if nothing else 118 | @if map-has-key($k-font-stacks, $stack) { 119 | @return join($fonts, map-get($k-font-stacks, $stack), comma); 120 | } @else { 121 | @warn "Font stack not found: '#{$stack}'."; 122 | @if map-has-key($k-font-stacks, $k-font-stack-default) { 123 | @return join($fonts, map-get($k-font-stacks, $stack), comma); 124 | } 125 | } 126 | 127 | // Font stack could not be found and default could not be loaded (since we're still here); issue another warning 128 | @warn "Font stacks could not be loaded."; 129 | 130 | // Don't just sit there, do something! 131 | @return monospace; 132 | } 133 | 134 | 135 | 136 | // Return a font stack without the generic term; used mainly to customize fallback fonts or add CJW fonts to the stack 137 | @function k-font-stack-trim($stack) { 138 | @if map-has-key($k-font-stacks, $stack) { 139 | @return set-nth(map-get($k-font-stacks, $stack), -1, null); 140 | } 141 | @warn "Font stack not found: '#{$stack}'."; 142 | @return (); 143 | } 144 | 145 | 146 | 147 | // A simple wrapper to output the complete font family declaration 148 | @mixin k-font-family($fonts...) { 149 | font-family: font-stack($fonts...); 150 | } 151 | --------------------------------------------------------------------------------