├── site ├── CNAME ├── robots.txt ├── ui │ ├── img │ │ └── favicon-1.png │ ├── app.scss │ └── _scss │ │ ├── foundation │ │ ├── components │ │ │ ├── _tables.scss │ │ │ ├── _grid.scss │ │ │ ├── _global.scss │ │ │ └── _type.scss │ │ └── _functions.scss │ │ └── _normalize.scss ├── _config.yml ├── _layouts │ ├── default.html │ └── compress.html └── index.md ├── test ├── source │ ├── _layouts │ ├── default │ │ ├── empty.html │ │ ├── strip.html │ │ ├── pre.html │ │ ├── tabs.html │ │ └── inline.html │ ├── startings │ │ ├── body.html │ │ ├── head.html │ │ └── head-html.html │ ├── profile │ │ └── whitespace.html │ ├── comments │ │ ├── inside.html │ │ ├── fake.html │ │ ├── outside.html │ │ ├── tags-own-line.html │ │ ├── real-fake.html │ │ ├── real-fake-real.html │ │ └── double-open.html │ ├── all │ │ ├── clippings.html │ │ ├── comments.html │ │ ├── successive-pre.html │ │ └── endings.html │ ├── ignore │ │ └── whitespace.html │ ├── conditional │ │ └── conditional.html │ ├── clippings │ │ └── whitespace-between-blocks.html │ ├── blanklines │ │ ├── prepre.html │ │ ├── endpre.html │ │ └── blanklines.html │ ├── endings │ │ └── table.html │ └── disabled │ │ ├── enabled.html │ │ └── disabled.html ├── _config.yml ├── expected │ ├── default │ │ ├── empty.html │ │ ├── strip.html │ │ ├── pre.html │ │ ├── tabs.html │ │ └── inline.html │ ├── all │ │ ├── comments.html │ │ ├── endings.html │ │ ├── clippings.html │ │ └── successive-pre.html │ ├── comments │ │ ├── inside.html │ │ ├── tags-own-line.html │ │ ├── double-open.html │ │ ├── outside.html │ │ ├── fake.html │ │ ├── real-fake.html │ │ └── real-fake-real.html │ ├── startings │ │ ├── head.html │ │ ├── body.html │ │ └── head-html.html │ ├── endings │ │ └── table.html │ ├── blanklines │ │ ├── prepre.html │ │ ├── endpre.html │ │ └── blanklines.html │ ├── conditional │ │ └── conditional.html │ ├── ignore │ │ └── whitespace.html │ ├── clippings │ │ └── whitespace-between-blocks.html │ ├── disabled │ │ ├── enabled.html │ │ └── disabled.html │ └── profile │ │ └── whitespace.html ├── _config_comments.yml ├── _startings.yml ├── _config_endings.yml ├── _config_ignore_all.yml ├── _config_clippings.yml ├── _config_conditional.yml ├── _config_ignore.yml ├── _config_blanklines.yml ├── _config_all.yml ├── _config_profile.yml └── test_filter.rb ├── performance ├── source │ ├── _layouts │ ├── motherfucking.html │ └── iiif-image.html ├── _config.yml ├── _config_compress.yml └── _config_blanklines.yml ├── .gitignore ├── src ├── compress.yaml └── compress.liquid ├── ISSUE_TEMPLATE.md ├── Gemfile ├── README.md ├── LICENSE ├── .github └── workflows │ └── tests.yml └── Rakefile /site/CNAME: -------------------------------------------------------------------------------- 1 | jch.penibelst.de 2 | -------------------------------------------------------------------------------- /test/source/_layouts: -------------------------------------------------------------------------------- 1 | ../../_build/ -------------------------------------------------------------------------------- /test/_config.yml: -------------------------------------------------------------------------------- 1 | source: source 2 | -------------------------------------------------------------------------------- /test/expected/default/empty.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /performance/source/_layouts: -------------------------------------------------------------------------------- 1 | ../../_build/ -------------------------------------------------------------------------------- /site/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /test/expected/all/comments.html: -------------------------------------------------------------------------------- 1 |
Two
2 | -------------------------------------------------------------------------------- /test/expected/comments/inside.html: -------------------------------------------------------------------------------- 1 |
Zero Two
2 | -------------------------------------------------------------------------------- /test/expected/startings/head.html: -------------------------------------------------------------------------------- 1 | One 2 | -------------------------------------------------------------------------------- /test/expected/comments/tags-own-line.html: -------------------------------------------------------------------------------- 1 |
One
2 | -------------------------------------------------------------------------------- /test/expected/startings/body.html: -------------------------------------------------------------------------------- 1 | One 2 | -------------------------------------------------------------------------------- /test/expected/startings/head-html.html: -------------------------------------------------------------------------------- 1 | One 2 | -------------------------------------------------------------------------------- /test/_config_comments.yml: -------------------------------------------------------------------------------- 1 | compress_html: 2 | comments: all 3 | -------------------------------------------------------------------------------- /test/_startings.yml: -------------------------------------------------------------------------------- 1 | compress_html: 2 | startings: [html, head] 3 | -------------------------------------------------------------------------------- /test/expected/default/strip.html: -------------------------------------------------------------------------------- 1 |
One
Two
2 | -------------------------------------------------------------------------------- /test/source/default/empty.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | -------------------------------------------------------------------------------- /test/expected/comments/double-open.html: -------------------------------------------------------------------------------- 1 | 1 --> 2 --> 3 4 5 6 7 --> 2 | -------------------------------------------------------------------------------- /test/expected/comments/outside.html: -------------------------------------------------------------------------------- 1 |
Zero
Two
2 | -------------------------------------------------------------------------------- /test/_config_endings.yml: -------------------------------------------------------------------------------- 1 | compress_html: 2 | endings: [li, p, tr, td] 3 | -------------------------------------------------------------------------------- /test/_config_ignore_all.yml: -------------------------------------------------------------------------------- 1 | compress_html: 2 | ignore: 3 | envs: all 4 | -------------------------------------------------------------------------------- /test/expected/all/endings.html: -------------------------------------------------------------------------------- 1 | One

Two

2 | -------------------------------------------------------------------------------- /test/expected/comments/fake.html: -------------------------------------------------------------------------------- 1 |
2 |   <!-- Two -->
3 | 
4 | -------------------------------------------------------------------------------- /test/expected/default/pre.html: -------------------------------------------------------------------------------- 1 |
One
2 |   Two
3 | 
4 | -------------------------------------------------------------------------------- /test/expected/default/tabs.html: -------------------------------------------------------------------------------- 1 |
One
Two
2 | -------------------------------------------------------------------------------- /test/_config_clippings.yml: -------------------------------------------------------------------------------- 1 | compress_html: 2 | clippings: [p, ul, li, div] 3 | -------------------------------------------------------------------------------- /test/_config_conditional.yml: -------------------------------------------------------------------------------- 1 | compress_html: 2 | comments: [""] 3 | -------------------------------------------------------------------------------- /test/_config_ignore.yml: -------------------------------------------------------------------------------- 1 | compress_html: 2 | ignore: 3 | envs: [ignore] 4 | -------------------------------------------------------------------------------- /test/expected/all/clippings.html: -------------------------------------------------------------------------------- 1 |
One Two Three
Four
2 | -------------------------------------------------------------------------------- /test/expected/comments/real-fake.html: -------------------------------------------------------------------------------- 1 |
2 |   <!-- Two -->
3 | 
4 | -------------------------------------------------------------------------------- /test/expected/endings/table.html: -------------------------------------------------------------------------------- 1 |
One
Two
2 | -------------------------------------------------------------------------------- /test/expected/blanklines/prepre.html: -------------------------------------------------------------------------------- 1 |
2 | TEXT

3 | 
4 | -------------------------------------------------------------------------------- /test/expected/comments/real-fake-real.html: -------------------------------------------------------------------------------- 1 |
2 |   <!-- Two -->
3 | 
4 | -------------------------------------------------------------------------------- /test/expected/default/inline.html: -------------------------------------------------------------------------------- 1 |
One Two Three Four
2 | -------------------------------------------------------------------------------- /test/_config_blanklines.yml: -------------------------------------------------------------------------------- 1 | compress_html: 2 | comments: all 3 | blanklines: true 4 | -------------------------------------------------------------------------------- /test/expected/all/successive-pre.html: -------------------------------------------------------------------------------- 1 |
2 |   
3 |   
4 |   
5 | 
6 | -------------------------------------------------------------------------------- /test/expected/conditional/conditional.html: -------------------------------------------------------------------------------- 1 |
Eight
2 | -------------------------------------------------------------------------------- /test/expected/ignore/whitespace.html: -------------------------------------------------------------------------------- 1 |
One
2 | 3 | 4 |
Two
5 | 6 | -------------------------------------------------------------------------------- /performance/_config.yml: -------------------------------------------------------------------------------- 1 | source: source 2 | compress_html: 3 | ignore: 4 | envs: [performance] 5 | -------------------------------------------------------------------------------- /test/_config_all.yml: -------------------------------------------------------------------------------- 1 | compress_html: 2 | clippings: all 3 | endings: all 4 | comments: all 5 | -------------------------------------------------------------------------------- /test/source/startings/body.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 | One 6 | -------------------------------------------------------------------------------- /test/source/startings/head.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 | One 6 | -------------------------------------------------------------------------------- /test/source/profile/whitespace.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |

One Two Three

6 | -------------------------------------------------------------------------------- /test/source/comments/inside.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
Zero Two
6 | -------------------------------------------------------------------------------- /test/source/startings/head-html.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 | One 6 | -------------------------------------------------------------------------------- /site/ui/img/favicon-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penibelst/jekyll-compress-html/HEAD/site/ui/img/favicon-1.png -------------------------------------------------------------------------------- /test/expected/clippings/whitespace-between-blocks.html: -------------------------------------------------------------------------------- 1 |
One
Two
Three
2 | -------------------------------------------------------------------------------- /test/source/comments/fake.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
6 |   <!-- Two -->
7 | 
8 | -------------------------------------------------------------------------------- /test/source/default/strip.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
One
Two
6 | 7 | 8 | -------------------------------------------------------------------------------- /test/source/comments/outside.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
Zero
Two
6 | -------------------------------------------------------------------------------- /test/source/comments/tags-own-line.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
One
8 | -------------------------------------------------------------------------------- /test/source/default/pre.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
One
6 |
7 |   Two
8 | 
9 | -------------------------------------------------------------------------------- /test/source/all/clippings.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
One Two Three
Four
6 | -------------------------------------------------------------------------------- /test/source/all/comments.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
Two
6 | -------------------------------------------------------------------------------- /test/source/default/tabs.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
6 |
One
7 |
Two
8 |
9 | -------------------------------------------------------------------------------- /test/source/ignore/whitespace.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
One
6 | 7 | 8 |
Two
9 | -------------------------------------------------------------------------------- /test/source/comments/real-fake.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 | 6 |
7 |   <!-- Two -->
8 | 
9 | -------------------------------------------------------------------------------- /test/source/conditional/conditional.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
Eight
6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | _build/ 3 | _site/ 4 | .sass-cache/ 5 | vnu.zip 6 | vnu/ 7 | _gh-pages/ 8 | .jekyll-metadata 9 | *~ 10 | -------------------------------------------------------------------------------- /test/source/all/successive-pre.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
 6 |   
 7 |   
 8 |   
 9 | 
10 | -------------------------------------------------------------------------------- /test/_config_profile.yml: -------------------------------------------------------------------------------- 1 | time: "2015-06-19" 2 | compress_html: 3 | clippings: all 4 | endings: all 5 | comments: all 6 | profile: true 7 | -------------------------------------------------------------------------------- /test/source/clippings/whitespace-between-blocks.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
One
Two
Three
6 | -------------------------------------------------------------------------------- /test/source/default/inline.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
One 6 | Two 7 | Three 8 | Four 9 |
10 | -------------------------------------------------------------------------------- /test/source/blanklines/prepre.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
6 | 7 | TEXT 8 |

 9 | 
10 | 

11 | 
12 | 
13 | -------------------------------------------------------------------------------- /test/source/all/endings.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 | 6 | One 7 | 8 | 9 |

Two

10 | 11 | -------------------------------------------------------------------------------- /test/source/comments/real-fake-real.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 | 6 |
 7 |   <!-- Two -->
 8 | 
9 | 10 | -------------------------------------------------------------------------------- /test/expected/disabled/enabled.html: -------------------------------------------------------------------------------- 1 |
One Two Three
Four
Two
One

Two

2 |   
3 |   
4 |   
5 | 
6 | -------------------------------------------------------------------------------- /performance/_config_compress.yml: -------------------------------------------------------------------------------- 1 | source: source 2 | compress_html: 3 | clippings: [div] 4 | comments: [""] 5 | endings: [li, dt, dd, p, thead, tbody, tr, td, th] 6 | profile: true 7 | -------------------------------------------------------------------------------- /test/source/endings/table.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
One
Two
13 | -------------------------------------------------------------------------------- /src/compress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Jekyll layout that compresses HTML 3 | # v3.2.1 4 | # http://jch.penibelst.de/ 5 | # © 2014–2015 Anatol Broder 6 | # MIT License 7 | --- 8 | 9 | {% capture _LINE_FEED %} 10 | -------------------------------------------------------------------------------- /site/_config.yml: -------------------------------------------------------------------------------- 1 | sass: 2 | sass_dir: ui/_scss 3 | style: compressed 4 | compress_html: 5 | clippings: all 6 | comments: all 7 | endings: all 8 | profile: true 9 | startings: [head, body] 10 | -------------------------------------------------------------------------------- /performance/_config_blanklines.yml: -------------------------------------------------------------------------------- 1 | source: source 2 | compress_html: 3 | clippings: [div] 4 | comments: [""] 5 | endings: [li, dt, dd, p, thead, tbody, tr, td, th] 6 | profile: true 7 | blanklines: true 8 | -------------------------------------------------------------------------------- /test/source/comments/double-open.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 | 1 --> 6 | 2 --> 7 | 3 8 | 4 9 | 5 10 | 6 abc --> 11 | 7 --> 12 | -------------------------------------------------------------------------------- /test/expected/blanklines/endpre.html: -------------------------------------------------------------------------------- 1 |
 2 |     hehe
 3 |     
4 | woot
 5 |     
 6 |     
 7 |     
 8 |     
    
 9 | 
10 |     
11 | 
12 | 
13 |     Woot
14 | 
15 | 
16 | 
17 |     
18 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please do not raise an issue if you have 2 | complaints about inline Javascript. 3 | 4 | Inline Javascript/CSS are out of scope for JCH for a variety of 5 | reasons including (But not limited to) performance, scale, and 6 | the fact that you can always just link the file 7 | -------------------------------------------------------------------------------- /test/source/blanklines/endpre.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 |
 6 |     hehe
 7 |     
8 | woot
 9 |     
10 |     
11 |     
12 |     
    
13 | 
14 |     
15 | 
16 | 
17 |     Woot
18 | 
19 | 
20 | 
21 |     
22 | -------------------------------------------------------------------------------- /test/expected/profile/whitespace.html: -------------------------------------------------------------------------------- 1 |

One Two Three

Step Bytes
raw 25
endings 26
comments 26
collapse 22
clippings 21
2 | -------------------------------------------------------------------------------- /test/expected/disabled/disabled.html: -------------------------------------------------------------------------------- 1 |
One Two Three
Four
2 |
Two
3 | 4 | One 5 | 6 | 7 |

Two

8 | 9 | 10 |
11 |   
12 |   
13 |   
14 | 
15 | 16 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "jekyll", ENV['JEKYLL_VERSION'] ? "~>#{ENV['JEKYLL_VERSION']}" : nil 4 | 5 | group :test do 6 | gem "rake" 7 | gem "minitest" 8 | gem "html-proofer", ">= 4", "< 6" 9 | end 10 | 11 | if ENV['USE_KRAMDOWN'] then 12 | gem "kramdown-parser-gfm" 13 | end 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Compress HTML in Jekyll][site] 2 | 3 | [![Build Status](https://travis-ci.org/penibelst/jekyll-compress-html.svg?branch=master)](https://travis-ci.org/penibelst/jekyll-compress-html) 4 | 5 | * [Documentation][site] 6 | * [Download](https://github.com/penibelst/jekyll-compress-html/releases/latest) 7 | 8 | [site]: http://jch.penibelst.de/ 9 | -------------------------------------------------------------------------------- /test/source/disabled/enabled.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | compress_html: true 4 | --- 5 | 6 |
One Two Three
Four
7 |
Two
8 | 9 | One 10 | 11 | 12 |

Two

13 | 14 | 15 |
16 |   
17 |   
18 |   
19 | 
20 | -------------------------------------------------------------------------------- /test/source/disabled/disabled.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | compress_html: false 4 | --- 5 | 6 |
One Two Three
Four
7 |
Two
8 | 9 | One 10 | 11 | 12 |

Two

13 | 14 | 15 |
16 |   
17 |   
18 |   
19 | 
20 | -------------------------------------------------------------------------------- /test/expected/blanklines/blanklines.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | A test of human 7 | readable compression 8 | 9 | 10 | 11 | 23 |
24 |        
25 |         These newlines should be kept
26 |         
27 |         See?
28 | 
29 |     
30 |     
31 |     
32 | Text 33 |
34 |     
35 |     
36 | 
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /site/_layouts/default.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 | 6 | 7 | 8 | 9 | 10 | {{ page.title }} 11 | 12 | 13 | {% if page.prefetch %} 14 | 15 | 16 | {% endif %} 17 | 18 | 19 | 20 |
21 |
22 |

{{ page.title }}

23 | {{ content }} 24 |
25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /test/source/blanklines/blanklines.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: compress 3 | --- 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | A test of human 13 | readable compression 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 |
32 |        
33 |         These newlines should be kept
34 |         
35 |         See?
36 | 
37 |     
38 |     
39 |     
40 | 41 | 42 | 43 | Text 44 | 45 | 46 | 47 |
48 |     
49 |     
50 | 
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /site/ui/app.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | @import "normalize"; 5 | 6 | /* 7 | Foundation 8 | docs: http://foundation.zurb.com/docs/ 9 | repo: https://github.com/zurb/bower-foundation 10 | */ 11 | 12 | /* settings */ 13 | $code-border-style: none; 14 | 15 | @import "foundation/components/grid"; 16 | @import "foundation/components/tables"; 17 | @import "foundation/components/type"; 18 | 19 | /* own styles */ 20 | 21 | /* zoom on large screens */ 22 | @media (min-width: 62.5em) { 23 | html { 24 | font-size: 1.6vw; 25 | } 26 | } 27 | 28 | h1 { 29 | margin-top: 1rem; 30 | } 31 | 32 | pre { 33 | margin-bottom: $paragraph-margin-bottom; 34 | } 35 | 36 | pre code { 37 | display: block; 38 | padding: $paragraph-margin-bottom; 39 | overflow-x: auto; 40 | } 41 | 42 | td, th { 43 | vertical-align: top; 44 | } 45 | 46 | .status { 47 | height: rem-calc(20); 48 | } 49 | 50 | /* profile */ 51 | 52 | table.compress_html_profile tbody td:last-child { 53 | text-align: right; 54 | } 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Anatol Broder 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [push, pull_request] 3 | jobs: 4 | tests: 5 | runs-on: ubuntu-latest 6 | strategy: 7 | fail-fast: false 8 | matrix: 9 | include: 10 | - jekyll: '2.0' 11 | ruby: '2.6' 12 | - jekyll: '2.1' 13 | ruby: '2.6' 14 | - jekyll: '3.0' 15 | ruby: '3.3' 16 | env: 17 | USE_KRAMDOWN: 1 18 | - jekyll: '4.0' 19 | ruby: '3.3' 20 | savebuild: true 21 | env: 22 | USE_KRAMDOWN: 1 23 | name: 'Jekyll ${{ matrix.jekyll }} on ruby ${{ matrix.ruby }}' 24 | env: 25 | JEKYLL_VERSION: ${{ matrix.jekyll }} 26 | steps: 27 | - uses: actions/checkout@v4 28 | - uses: ruby/setup-ruby@v1 29 | with: 30 | ruby-version: ${{ matrix.ruby }} 31 | - run: bundle install 32 | - run: bundle exec rake test 33 | - uses: actions/upload-artifact@v4 34 | with: 35 | name: compress.html 36 | path: _build/compress.html 37 | if: ${{ matrix.savebuild }} 38 | site: 39 | runs-on: ubuntu-latest 40 | name: 'Build site' 41 | needs: 42 | - tests 43 | steps: 44 | - uses: actions/checkout@v4 45 | - uses: ruby/setup-ruby@v1 46 | with: 47 | ruby-version: ruby 48 | - run: bundle install 49 | - run: bundle exec rake site:test 50 | -------------------------------------------------------------------------------- /test/test_filter.rb: -------------------------------------------------------------------------------- 1 | require "minitest/autorun" 2 | 3 | class TestCompressed < Minitest::Test 4 | 5 | def setup 6 | Dir.glob File.join(COMPRESSED_DIR, "**", "*.html") do |path| 7 | File.delete path if File.file? path 8 | end 9 | end 10 | 11 | def test_default 12 | jekyll_build ["_config.yml"] 13 | assert_dir "default" 14 | end 15 | 16 | def test_all 17 | jekyll_build ["_config.yml", "_config_all.yml"] 18 | assert_dir "all" 19 | end 20 | 21 | def test_disabled 22 | jekyll_build ["_config.yml", "_config_all.yml"] 23 | assert_dir "disabled" 24 | end 25 | 26 | def test_clippings 27 | jekyll_build ["_config.yml", "_config_clippings.yml"] 28 | assert_dir "clippings" 29 | end 30 | 31 | def test_endings 32 | jekyll_build ["_config.yml", "_config_endings.yml"] 33 | assert_dir "endings" 34 | end 35 | 36 | def test_comments 37 | jekyll_build ["_config.yml", "_config_comments.yml"] 38 | assert_dir "comments" 39 | end 40 | 41 | def test_conditional 42 | jekyll_build ["_config.yml", "_config_conditional.yml"] 43 | assert_dir "conditional" 44 | end 45 | 46 | def test_profile 47 | jekyll_build ["_config.yml", "_config_profile.yml"] 48 | assert_dir "profile" 49 | end 50 | 51 | def test_ignore 52 | ENV["JEKYLL_ENV"] = "ignore" 53 | jekyll_build ["_config.yml", "_config_ignore.yml"] 54 | assert_dir "ignore" 55 | ENV["JEKYLL_ENV"] = nil 56 | end 57 | 58 | def test_ignore_all 59 | ENV["JEKYLL_ENV"] = "production" 60 | jekyll_build ["_config.yml", "_config_ignore_all.yml"] 61 | assert_dir "ignore" 62 | ENV["JEKYLL_ENV"] = nil 63 | end 64 | 65 | def test_startings 66 | jekyll_build ["_config.yml", "_startings.yml"] 67 | assert_dir "startings" 68 | end 69 | 70 | def test_blanklines 71 | jekyll_build ["_config.yml", "_config_blanklines.yml"] 72 | assert_dir "blanklines" 73 | end 74 | 75 | private 76 | 77 | EXPECTED_DIR = File.join File.dirname(__FILE__), "expected" 78 | COMPRESSED_DIR = File.join File.dirname(__FILE__), "_site" 79 | 80 | def assert_dir(dir) 81 | Dir.glob File.join(EXPECTED_DIR, dir, "*.html") do |path| 82 | assert_equal File.new(path).read, File.new(path.gsub(EXPECTED_DIR, COMPRESSED_DIR)).read, File.basename(path) 83 | end 84 | end 85 | 86 | def jekyll_build(configs) 87 | Dir.chdir File.dirname(__FILE__) do 88 | %x{bundle exec jekyll build --config #{configs.join(",")}} 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "rake" 2 | require "rake/testtask" 3 | require "rake/clean" 4 | 5 | task :default => [:test] 6 | 7 | BUILD_DIR = "_build" 8 | BUILD_FILE = File.join(BUILD_DIR, "compress.html") 9 | 10 | directory BUILD_DIR 11 | file BUILD_FILE => FileList["src/compress.*", BUILD_DIR] do |bf| 12 | yaml = File.open("src/compress.yaml").read 13 | liquid = File.open("src/compress.liquid").read 14 | .gsub(/\s+/, " ") 15 | .gsub(/\s+(?={)|/, "") 16 | .gsub(/{% comment %}[^{]+{% endcomment %}/, "") 17 | .strip 18 | 19 | File.open bf.name, 'w' do |f| 20 | f.puts yaml, liquid 21 | end 22 | end 23 | 24 | Rake::TestTask.new :test => BUILD_FILE do |t| 25 | t.libs << "test" 26 | t.test_files = FileList["test/test_*.rb"] 27 | end 28 | 29 | task :performance => BUILD_FILE do 30 | require "benchmark" 31 | Dir.chdir "performance" do 32 | buildtimes = [ 33 | "Build:\t\t" + Benchmark.measure { sh "JEKYLL_ENV=performance bundler exec jekyll build" }.to_s, 34 | "Compress:\t" + Benchmark.measure { sh "bundle exec jekyll build --config _config_compress.yml" }.to_s, 35 | "Blanklines:\t" + Benchmark.measure { sh "bundle exec jekyll build --config _config_blanklines.yml" }.to_s 36 | ] 37 | puts buildtimes 38 | end 39 | end 40 | 41 | CLEAN.include FileList["vnu*", "Gemfile.lock", "**/_site"] 42 | CLOBBER.include FileList["_build/*", "_gh-pages"] 43 | 44 | namespace :site do 45 | task :build do 46 | Dir.chdir "site" do 47 | sh "bundle exec jekyll build" 48 | end 49 | end 50 | 51 | task :preview do 52 | Dir.chdir "site" do 53 | sh "bundle exec jekyll serve --drafts" 54 | end 55 | end 56 | 57 | VALIDATOR = "vnu/vnu.jar" 58 | file VALIDATOR do |f| 59 | sh "wget -O vnu.zip https://github.com/validator/validator/releases/download/20141006/vnu-20141013.jar.zip" 60 | sh "unzip vnu.zip #{f.name}" 61 | end 62 | 63 | task :validate => [:build, VALIDATOR] do 64 | sh "java -jar #{File.join(".", VALIDATOR)} ./site/_site" 65 | end 66 | 67 | task :proof => :build do 68 | require 'html-proofer' 69 | HTMLProofer.check_directory("./site/_site", { 70 | :verbose => true, 71 | :typhoeus => { 72 | :ssl_verifypeer => false, 73 | :ssl_verifyhost => 0} 74 | }).run 75 | end 76 | 77 | task :test => [:validate, :proof] 78 | 79 | GH_PAGES_DIR = "_gh-pages" 80 | directory GH_PAGES_DIR 81 | file GH_PAGES_DIR do |f| 82 | sh "git clone git@github.com:penibelst/jekyll-compress-html #{f.name}" 83 | end 84 | 85 | desc "Commit the local site to the gh-pages branch and publish to GitHub Pages" 86 | task :publish => [GH_PAGES_DIR, :test] do 87 | Dir.chdir GH_PAGES_DIR do 88 | sh "git checkout gh-pages" 89 | sh "git pull origin gh-pages" 90 | end 91 | 92 | puts "Cleaning gh-pages directory..." 93 | rm_rf FileList[File.join(GH_PAGES_DIR, "**", "*")] 94 | 95 | puts "Copying site to gh-pages branch..." 96 | cp_r FileList[File.join("site", "*"), ".gitignore"], GH_PAGES_DIR 97 | 98 | puts "Committing and pushing to GitHub Pages..." 99 | sha = `git log`.match(/[a-z0-9]{40}/)[0] 100 | Dir.chdir GH_PAGES_DIR do 101 | sh "git add ." 102 | sh "git commit --allow-empty -m 'Updating to #{sha}.'" 103 | sh "git push origin gh-pages" 104 | end 105 | puts 'Done.' 106 | end 107 | end 108 | -------------------------------------------------------------------------------- /site/ui/_scss/foundation/components/_tables.scss: -------------------------------------------------------------------------------- 1 | // Foundation by ZURB 2 | // foundation.zurb.com 3 | // Licensed under MIT Open Source 4 | 5 | @import "global"; 6 | 7 | // 8 | // @name _tables.scss 9 | // @dependencies _global.scss 10 | // 11 | 12 | // 13 | // @variables 14 | // 15 | 16 | $include-html-table-classes: $include-html-classes !default; 17 | 18 | // These control the background color for the table and even rows 19 | $table-bg: $white !default; 20 | $table-even-row-bg: $snow !default; 21 | 22 | // These control the table cell border style 23 | $table-border-style: solid !default; 24 | $table-border-size: 1px !default; 25 | $table-border-color: $gainsboro !default; 26 | 27 | // These control the table head styles 28 | $table-head-bg: $white-smoke !default; 29 | $table-head-font-size: rem-calc(14) !default; 30 | $table-head-font-color: $jet !default; 31 | $table-head-font-weight: $font-weight-bold !default; 32 | $table-head-padding: rem-calc(8 10 10) !default; 33 | 34 | // These control the table foot styles 35 | $table-foot-bg: $table-head-bg !default; 36 | $table-foot-font-size: $table-head-font-size !default; 37 | $table-foot-font-color: $table-head-font-color !default; 38 | $table-foot-font-weight: $table-head-font-weight !default; 39 | $table-foot-padding: $table-head-padding !default; 40 | 41 | // These control the caption 42 | $table-caption-bg: transparent !default; 43 | $table-caption-font-color: $table-head-font-color !default; 44 | $table-caption-font-size: rem-calc(16) !default; 45 | $table-caption-font-weight: bold !default; 46 | 47 | // These control the row padding and font styles 48 | $table-row-padding: rem-calc(9 10) !default; 49 | $table-row-font-size: rem-calc(14) !default; 50 | $table-row-font-color: $jet !default; 51 | $table-line-height: rem-calc(18) !default; 52 | 53 | // These are for controlling the layout, display and margin of tables 54 | $table-layout: auto !default; 55 | $table-display: table-cell !default; 56 | $table-margin-bottom: rem-calc(20) !default; 57 | 58 | 59 | // 60 | // @mixins 61 | // 62 | 63 | @mixin table { 64 | background: $table-bg; 65 | margin-bottom: $table-margin-bottom; 66 | border: $table-border-style $table-border-size $table-border-color; 67 | table-layout: $table-layout; 68 | 69 | caption { 70 | background: $table-caption-bg; 71 | color: $table-caption-font-color; 72 | font: { 73 | size: $table-caption-font-size; 74 | weight: $table-caption-font-weight; 75 | } 76 | } 77 | 78 | thead { 79 | background: $table-head-bg; 80 | 81 | tr { 82 | th, 83 | td { 84 | padding: $table-head-padding; 85 | font-size: $table-head-font-size; 86 | font-weight: $table-head-font-weight; 87 | color: $table-head-font-color; 88 | } 89 | } 90 | } 91 | 92 | tfoot { 93 | background: $table-foot-bg; 94 | 95 | tr { 96 | th, 97 | td { 98 | padding: $table-foot-padding; 99 | font-size: $table-foot-font-size; 100 | font-weight: $table-foot-font-weight; 101 | color: $table-foot-font-color; 102 | } 103 | } 104 | } 105 | 106 | tr { 107 | th, 108 | td { 109 | padding: $table-row-padding; 110 | font-size: $table-row-font-size; 111 | color: $table-row-font-color; 112 | text-align: $default-float; 113 | } 114 | 115 | &.even, 116 | &.alt, 117 | &:nth-of-type(even) { background: $table-even-row-bg; } 118 | } 119 | 120 | thead tr th, 121 | tfoot tr th, 122 | tfoot tr td, 123 | tbody tr th, 124 | tbody tr td, 125 | tr td { display: $table-display; line-height: $table-line-height; } 126 | } 127 | 128 | 129 | @include exports("table") { 130 | @if $include-html-table-classes { 131 | table { 132 | @include table; 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /site/ui/_scss/foundation/_functions.scss: -------------------------------------------------------------------------------- 1 | // Foundation by ZURB 2 | // foundation.zurb.com 3 | // Licensed under MIT Open Source 4 | 5 | // This is the default html and body font-size for the base rem value. 6 | $rem-base: 16px !default; 7 | 8 | // IMPORT ONCE 9 | // We use this to prevent styles from being loaded multiple times for compenents that rely on other components. 10 | $modules: () !default; 11 | @mixin exports($name) { 12 | // Import from global scope 13 | $modules: $modules !global; 14 | // Check if a module is already on the list 15 | $module_index: index($modules, $name); 16 | @if (($module_index == null) or ($module_index == false)) { 17 | $modules: append($modules, $name) !global; 18 | @content; 19 | } 20 | } 21 | 22 | // 23 | // @functions 24 | // 25 | 26 | 27 | // RANGES 28 | // We use these functions to define ranges for various things, like media queries. 29 | @function lower-bound($range){ 30 | @if length($range) <= 0 { 31 | @return 0; 32 | } 33 | @return nth($range,1); 34 | } 35 | 36 | @function upper-bound($range) { 37 | @if length($range) < 2 { 38 | @return 999999999999; 39 | } 40 | @return nth($range, 2); 41 | } 42 | 43 | // STRIP UNIT 44 | // It strips the unit of measure and returns it 45 | @function strip-unit($num) { 46 | @return $num / ($num * 0 + 1); 47 | } 48 | 49 | // TEXT INPUT TYPES 50 | 51 | @function text-inputs( $types: all, $selector: input ) { 52 | 53 | $return: (); 54 | 55 | $all-text-input-types: 56 | text 57 | password 58 | date 59 | datetime 60 | datetime-local 61 | month 62 | week 63 | email 64 | number 65 | search 66 | tel 67 | time 68 | url 69 | color 70 | textarea; 71 | 72 | @if $types == all { $types: $all-text-input-types; } 73 | 74 | @each $type in $types { 75 | @if $type == textarea { 76 | @if $selector == input { 77 | $return: append($return, unquote('#{$type}'), comma) 78 | } @else { 79 | $return: append($return, unquote('#{$type}#{$selector}'), comma) 80 | } 81 | } @else { 82 | $return: append($return, unquote('#{$selector}[type="#{$type}"]'), comma) 83 | } 84 | } 85 | 86 | @return $return; 87 | 88 | } 89 | 90 | // CONVERT TO REM 91 | @function convert-to-rem($value, $base-value: $rem-base) { 92 | $value: strip-unit($value) / strip-unit($base-value) * 1rem; 93 | @if ($value == 0rem) { $value: 0; } // Turn 0rem into 0 94 | @return $value; 95 | } 96 | 97 | @function data($attr) { 98 | @if $namespace { 99 | @return '[data-' + $namespace + '-' + $attr + ']'; 100 | } 101 | 102 | @return '[data-' + $attr + ']'; 103 | } 104 | 105 | // REM CALC 106 | 107 | // New Syntax, allows to optionally calculate on a different base value to counter compounding effect of rem's. 108 | // Call with 1, 2, 3 or 4 parameters, 'px' is not required but supported: 109 | // 110 | // rem-calc(10 20 30px 40); 111 | // 112 | // Space delimited, if you want to delimit using comma's, wrap it in another pair of brackets 113 | // 114 | // rem-calc((10, 20, 30, 40px)); 115 | // 116 | // Optionally call with a different base (eg: 8px) to calculate rem. 117 | // 118 | // rem-calc(16px 32px 48px, 8px); 119 | // 120 | // If you require to comma separate your list 121 | // 122 | // rem-calc((16px, 32px, 48), 8px); 123 | 124 | @function rem-calc($values, $base-value: $rem-base) { 125 | $max: length($values); 126 | 127 | @if $max == 1 { @return convert-to-rem(nth($values, 1), $base-value); } 128 | 129 | $remValues: (); 130 | @for $i from 1 through $max { 131 | $remValues: append($remValues, convert-to-rem(nth($values, $i), $base-value)); 132 | } 133 | @return $remValues; 134 | } 135 | 136 | // OLD EM CALC 137 | // Deprecated: We'll drop support for this in 5.1.0, use rem-calc() 138 | @function emCalc($values){ 139 | @return rem-calc($values); 140 | } 141 | 142 | // OLD EM CALC 143 | // Deprecated: We'll drop support for this in 5.1.0, use rem-calc() 144 | @function em-calc($values){ 145 | @return rem-calc($values); 146 | } 147 | -------------------------------------------------------------------------------- /site/_layouts/compress.html: -------------------------------------------------------------------------------- 1 | --- 2 | # Jekyll layout that compresses HTML 3 | # v3.0.1 4 | # http://jch.penibelst.de/ 5 | # © 2014–2015 Anatol Broder 6 | # MIT License 7 | --- 8 | 9 | {% capture _LINE_FEED %} 10 | {% endcapture %}{% if site.compress_html.ignore.envs contains jekyll.environment %}{{ content }}{% else %}{% capture _content %}{{ content }}{% endcapture %}{% assign _profile = site.compress_html.profile %}{% if site.compress_html.endings == "all" %}{% assign _endings = "html head body li dt dd p rt rp optgroup option colgroup caption thead tbody tfoot tr td th" | split: " " %}{% else %}{% assign _endings = site.compress_html.endings %}{% endif %}{% for _element in _endings %}{% capture _end %}{% endcapture %}{% assign _content = _content | remove: _end %}{% endfor %}{% if _profile and _endings %}{% assign _profile_endings = _content | size | plus: 1 %}{% endif %}{% for _element in site.compress_html.startings %}{% capture _start %}<{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _start %}{% endfor %}{% if _profile and site.compress_html.startings %}{% assign _profile_startings = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.comments == "all" %}{% assign _comments = "" | split: " " %}{% else %}{% assign _comments = site.compress_html.comments %}{% endif %}{% if _comments.size == 2 %}{% capture _comment_befores %}.{{ _content }}{% endcapture %}{% assign _comment_befores = _comment_befores | split: _comments.first %}{% for _comment_before in _comment_befores %}{% if forloop.first %}{% continue %}{% endif %}{% capture _comment_outside %}{% if _carry %}{{ _comments.first }}{% endif %}{{ _comment_before }}{% endcapture %}{% capture _comment %}{% unless _carry %}{{ _comments.first }}{% endunless %}{{ _comment_outside | split: _comments.last | first }}{% if _comment_outside contains _comments.last %}{{ _comments.last }}{% assign _carry = false %}{% else %}{% assign _carry = true %}{% endif %}{% endcapture %}{% assign _content = _content | remove_first: _comment %}{% endfor %}{% if _profile %}{% assign _profile_comments = _content | size | plus: 1 %}{% endif %}{% endif %}{% assign _pre_befores = _content | split: "" %}{% assign _pres_after = "" %}{% if _pres.size != 0 %}{% if site.compress_html.blanklines %}{% assign _lines = _pres.last | split: _LINE_FEED %}{% assign _lastchar = _pres.last | split: "" | last %}{% assign _outerloop = forloop %}{% capture _pres_after %}{% for _line in _lines %}{% assign _trimmed = _line | split: " " | join: " " %}{% if forloop.last and _lastchar == _LINE_FEED %}{% unless _outerloop.last %}{{ _LINE_FEED }}{% endunless %}{% continue %}{% endif %}{% if _trimmed != empty or forloop.last %}{% unless forloop.first %}{{ _LINE_FEED }}{% endunless %}{{ _line }}{% endif %}{% endfor %}{% endcapture %}{% else %}{% assign _pres_after = _pres.last | split: " " | join: " " %}{% endif %}{% endif %}{% capture _content %}{{ _content }}{% if _pre_before contains "" %}{% endif %}{% unless _pre_before contains "" and _pres.size == 1 %}{{ _pres_after }}{% endunless %}{% endcapture %}{% endfor %}{% if _profile %}{% assign _profile_collapse = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.clippings == "all" %}{% assign _clippings = "html head title base link meta style body article section nav aside h1 h2 h3 h4 h5 h6 hgroup header footer address p hr blockquote ol ul li dl dt dd figure figcaption main div table caption colgroup col tbody thead tfoot tr td th" | split: " " %}{% else %}{% assign _clippings = site.compress_html.clippings %}{% endif %}{% for _element in _clippings %}{% assign _edges = " ;; ;" | replace: "e", _element | split: ";" %}{% assign _content = _content | replace: _edges[0], _edges[1] | replace: _edges[2], _edges[3] | replace: _edges[4], _edges[5] %}{% endfor %}{% if _profile and _clippings %}{% assign _profile_clippings = _content | size | plus: 1 %}{% endif %}{{ _content }}{% if _profile %}
Step Bytes
raw {{ content | size }}{% if _profile_endings %}
endings {{ _profile_endings }}{% endif %}{% if _profile_startings %}
startings {{ _profile_startings }}{% endif %}{% if _profile_comments %}
comments {{ _profile_comments }}{% endif %}{% if _profile_collapse %}
collapse {{ _profile_collapse }}{% endif %}{% if _profile_clippings %}
clippings {{ _profile_clippings }}{% endif %}
{% endif %}{% endif %} 11 | -------------------------------------------------------------------------------- /performance/source/motherfucking.html: -------------------------------------------------------------------------------- 1 | --- 2 | # Example of a motherfucking page 3 | # http://motherfuckingwebsite.com/ 4 | # © 2013 Barry Smith 5 | # Permission: https://twitter.com/thebarrytone/status/477040526165016577 6 | # 7 | layout: compress 8 | --- 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Motherfucking Website 19 | 20 | 21 | 22 |
23 |

This is a motherfucking website.

24 | 25 |
26 | 27 |

Seriously, what the fuck else do you want?

28 | 29 |

You probably build websites and think your shit is special. You think your 13 megabyte parallax-ative home page is going to get you some fucking Awwward banner you can glue to the top corner of your site. You think your 40-pound jQuery file and 83 polyfills give IE7 a boner because it finally has box-shadow. Wrong, motherfucker. Let me describe your perfect-ass website:

30 | 31 |
    32 |
  • Shit's lightweight and loads fast
  • 33 |
  • Fits on all your shitty screens
  • 34 |
  • Looks the same in all your shitty browsers
  • 35 |
  • The motherfucker's accessible to every asshole that visits your site
  • 36 |
  • Shit's legible and gets your fucking point across (if you had one instead of just 5mb pics of hipsters drinking coffee)
  • 37 |
38 | 39 |

Well guess what, motherfucker:

40 | 41 |

You. Are. Over-designing. Look at this shit. It's a motherfucking website. Why the fuck do you need to animate a fucking trendy-ass banner flag when I hover over that useless piece of shit? You spent hours on it and added 80 kilobytes to your fucking site, and some motherfucker jabbing at it on their iPad with fat sausage fingers will never see that shit. Not to mention blind people will never see that shit, but they don't see any of your shitty shit.

42 | 43 |

You never knew it, but this is your perfect website. Here's why.

44 | 45 |

It's fucking lightweight

46 | 47 |

This entire page weighs less than the gradient-meshed facebook logo on your fucking Wordpress site. Did you seriously load 100kb of jQuery UI just so you could animate the fucking background color of a div? You loaded all 7 fontfaces of a shitty webfont just so you could say "Hi." at 100px height at the beginning of your site? You piece of shit.

48 | 49 |

It's responsive

50 | 51 |

You dumbass. You thought you needed media queries to be responsive, but no. Responsive means that it responds to whatever motherfucking screensize it's viewed on. This site doesn't care if you're on an iMac or a motherfucking Tamagotchi.

52 | 53 |

It fucking works

54 | 55 |

Look at this shit. You can read it ... that is, if you can read, motherfucker. It makes sense. It has motherfucking hierarchy. It's using HTML5 tags so you and your bitch-ass browser know what the fuck's in this fucking site. That's semantics, motherfucker.

56 | 57 |

It has content on the fucking screen. Your site has three bylines and link to your dribbble account, but you spread it over 7 full screens and make me click some bobbing button to show me how cool the jQuery ScrollTo plugin is.

58 | 59 |

Cross-browser compatibility? Load this motherfucker in IE6. I fucking dare you.

60 | 61 |

This is a website. Look at it. You've never seen one before.

62 | 63 |

Like the pansy-ass who's never grown out his beard has no idea what his true natural state is, you have no fucking idea what a website is. All you have ever seen are shitty skeuomorphic bastardizations of what should be text communicating a fucking message. This is a real, naked website. Look at it. It's fucking beautiful.

64 | 65 |

Yes, this is fucking satire, you fuck

66 | 67 |

I'm not actually saying your shitty site should look like this. What I'm saying is that all the problems we have with websites are ones we create ourselves. Websites aren't broken by default, they are functional, high-performing, and accessible. You break them. You son-of-a-bitch.

68 | 69 |
"Good design is as little design as possible."
70 | - some German motherfucker 71 |
72 | 73 |
74 | 75 |

Epilogue

76 |

This site was made by @thebarrytone, and from the philosophies expressed (poorly) above, he created txti. You should try it today to make your own motherfucking websites.

77 | 78 | 79 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/compress.liquid: -------------------------------------------------------------------------------- 1 | {% endcapture %} 2 | 3 | {% if site.compress_html.ignore.envs contains jekyll.environment or site.compress_html.ignore.envs == "all" or page.compress_html == false %} 4 | {{ content }} 5 | {% else %} 6 | 7 | 8 | {% comment %}Initialization{% endcomment %} 9 | 10 | {% capture _content %}{{ content }}{% endcapture %} 11 | {% assign _profile = site.compress_html.profile %} 12 | 13 | 14 | {% comment %}Remove end tags{% endcomment %} 15 | 16 | {% if site.compress_html.endings == "all" %} 17 | {% assign _endings = "html head body li dt dd optgroup option colgroup caption thead tbody tfoot tr td th" | split: " " %} 18 | {% else %} 19 | {% assign _endings = site.compress_html.endings %} 20 | {% endif %} 21 | {% for _element in _endings %} 22 | {% capture _end %}{% endcapture %} 23 | {% assign _content = _content | remove: _end %} 24 | {% endfor %} 25 | {% if _profile and _endings %} 26 | {% assign _profile_endings = _content | size | plus: 1 %} 27 | {% endif %} 28 | 29 | 30 | {% comment %}Remove start tags{% endcomment %} 31 | 32 | {% for _element in site.compress_html.startings %} 33 | {% capture _start %}<{{ _element }}>{% endcapture %} 34 | {% assign _content = _content | remove: _start %} 35 | {% endfor %} 36 | {% if _profile and site.compress_html.startings %} 37 | {% assign _profile_startings = _content | size | plus: 1 %} 38 | {% endif %} 39 | 40 | 41 | {% comment %}Remove comments{% endcomment %} 42 | 43 | {% if site.compress_html.comments == "all" %} 44 | {% assign _comments = "" | split: " " %} 45 | {% else %} 46 | {% assign _comments = site.compress_html.comments %} 47 | {% endif %} 48 | {% if _comments.size == 2 %} 49 | {% capture _comment_befores %}.{{ _content }}{% endcapture %} 50 | {% assign _comment_befores = _comment_befores | split: _comments.first %} 51 | {% for _comment_before in _comment_befores %} 52 | {% if forloop.first %} 53 | {% continue %} 54 | {% endif %} 55 | {% capture _comment_outside %} 56 | {% if _carry %}{{ _comments.first }}{% endif %} 57 | {{ _comment_before }} 58 | {% endcapture %} 59 | {% capture _comment %} 60 | {% unless _carry %}{{ _comments.first }}{% endunless %} 61 | {{ _comment_outside | split: _comments.last | first }} 62 | {% if _comment_outside contains _comments.last %} 63 | {{ _comments.last }} 64 | {% assign _carry = false %} 65 | {% else %} 66 | {% assign _carry = true %} 67 | {% endif %} 68 | {% endcapture %} 69 | {% assign _content = _content | remove_first: _comment %} 70 | {% endfor %} 71 | {% if _profile %} 72 | {% assign _profile_comments = _content | size | plus: 1 %} 73 | {% endif %} 74 | {% endif %} 75 | 76 | 77 | {% comment %}Collapse whitespace outside of
{% endcomment %}
 78 | 
 79 | {% assign _pre_befores = _content | split: "" %}
 83 |   {% assign _pres_after = "" %}
 84 | 
 85 |   {% if _pres.size != 0 %}
 86 |     {% if site.compress_html.blanklines %}
 87 |       {% assign _lines = _pres.last | split: _LINE_FEED %}
 88 |       {% capture _pres_after %}
 89 |         {% for _line in _lines %}
 90 |           {% assign _trimmed = _line | split: " " | join: " " %}
 91 |           {% if _trimmed != empty or forloop.last %}
 92 |             {% unless forloop.first %}
 93 |               {{ _LINE_FEED }}
 94 |             {% endunless %}
 95 |             {{ _line }}
 96 |           {% endif %}
 97 |         {% endfor %}
 98 |       {% endcapture %}
 99 |     {% else %}
100 |       {% assign _pres_after = _pres.last | split: " " | join: " " %}
101 |     {% endif %}
102 |   {% endif %}
103 | 
104 |   {% capture _content %}
105 |     {{ _content }}
106 |     {% if _pre_before contains "
" %}{% endif %} 107 | {% unless _pre_before contains "" and _pres.size == 1 %}{{ _pres_after }}{% endunless %} 108 | {% endcapture %} 109 | {% endfor %} 110 | {% if _profile %} 111 | {% assign _profile_collapse = _content | size | plus: 1 %} 112 | {% endif %} 113 | 114 | 115 | {% comment %}Clip whitespace around elements{% endcomment %} 116 | 117 | {% if site.compress_html.clippings == "all" %} 118 | {% assign _clippings = "html head title base link meta style body article section nav aside h1 h2 h3 h4 h5 h6 hgroup header footer address p hr blockquote ol ul li dl dt dd figure figcaption main div table caption colgroup col tbody thead tfoot tr td th" | split: " " %} 119 | {% else %} 120 | {% assign _clippings = site.compress_html.clippings %} 121 | {% endif %} 122 | {% for _element in _clippings %} 123 | {% assign _edges = " ;; ;" | replace: "e", _element | split: ";" %} 124 | {% assign _content = _content | replace: _edges[0], _edges[1] | replace: _edges[2], _edges[3] | replace: _edges[4], _edges[5] %} 125 | {% endfor %} 126 | {% if _profile and _clippings %} 127 | {% assign _profile_clippings = _content | size | plus: 1 %} 128 | {% endif %} 129 | 130 | 131 | {% comment %}Output{% endcomment %} 132 | 133 | {{ _content }} 134 | 135 | {% if _profile %} 136 | 137 | 138 | 140 |
Step Bytes 139 |
raw {{ content | size }} 141 | {% if _profile_endings %} 142 |
endings {{ _profile_endings }} 143 | {% endif %} 144 | {% if _profile_startings %} 145 |
startings {{ _profile_startings }} 146 | {% endif %} 147 | {% if _profile_comments %} 148 |
comments {{ _profile_comments }} 149 | {% endif %} 150 | {% if _profile_collapse %} 151 |
collapse {{ _profile_collapse }} 152 | {% endif %} 153 | {% if _profile_clippings %} 154 |
clippings {{ _profile_clippings }} 155 | {% endif %} 156 |
157 | {% endif %} 158 | 159 | {% endif %} 160 | -------------------------------------------------------------------------------- /site/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Compress HTML in Jekyll 3 | layout: default 4 | prefetch: "https://github.com/penibelst/jekyll-compress-html" 5 | --- 6 | 7 | A [Jekyll][jekyll] layout that compresses [HTML][html-spec]. At a glance: 8 | 9 | * removes unnecessary whitespace; 10 | * removes optional end tags; 11 | * removes optional start tags; 12 | * removes comments; 13 | * preserves whitespace within `
`;
 14 | * GitHub Pages compatible;
 15 | * ignores development environments;
 16 | * configurable affected elements;
 17 | * profile mode;
 18 | * automatically tested.
 19 | 
 20 | The layout is written in pure [Liquid][liquid], no plugins are required.
 21 | 
 22 | ## Installation
 23 | 
 24 | 1. Get the [latest release][github-repo-latest]. Extract `compress.html` and copy it to your `_layouts`.
 25 | 1. Reference the `compress` layout in your highest-level layout. For example in `_layouts/default.html`:
 26 | 
 27 | ~~~html
 28 | ---
 29 | layout: compress
 30 | ---
 31 | 
 32 | 
 33 | {% raw %}{{ content }}{% endraw %}
 34 | 
 35 | ~~~
 36 | 
 37 | Now all your markup will be processed by the `compress` layout.
 38 | 
 39 | You can disable compression on a page-by-page basis with the `compress_html` frontmatter. For example:
 40 | 
 41 | ```html
 42 | ---
 43 | compress_html: false
 44 | ---
 45 | 
 46 | This page will not be compressed
 47 | ```
 48 | 
 49 | ## Configuration
 50 | 
 51 | By default the layout replaces contiguous whitespace with a single whitespace character. Additional settings can be specified in the `compress_html` key inside the `_config.yml` file. The default configuration is:
 52 | 
 53 | ~~~yaml
 54 | compress_html:
 55 |   clippings: []
 56 |   comments: []
 57 |   endings: []
 58 |   ignore:
 59 |     envs: []
 60 |   blanklines: false
 61 |   profile: false
 62 |   startings: []
 63 | ~~~
 64 | 
 65 | ### clippings
 66 | 
 67 | An array of elements to clip whitespace around them. The following elements may be safe to clip:
 68 | 
 69 | * [Metadata content][html-semantics];
 70 | * [Sections][html-semantics];
 71 | * [Grouping content][html-semantics] except the `pre` element;
 72 | * [Tabular data][html-tabular].
 73 | 
 74 | Example:
 75 | 
 76 | ~~~yaml
 77 | compress_html:
 78 |   clippings: [div, p, ul, td, h1, h2]
 79 | ~~~
 80 | 
 81 | Use the shortcut `all` to clip all safe elements.
 82 | 
 83 | ~~~yaml
 84 | compress_html:
 85 |   clippings: all
 86 | ~~~
 87 | 
 88 | ### comments
 89 | 
 90 | An array of exactly two comment tags to strip comments enclosed by them. The first string must be the start tag, the second must be the end tag. Example:
 91 | 
 92 | ~~~yaml
 93 | compress_html:
 94 |   comments: [""]
 95 | ~~~
 96 | 
 97 | Whitespaces around the tags prevent [conditional comments][cond] from being deleted.
 98 | 
 99 | Use the shortcut `all` to remove all comments.
100 | 
101 | ### endings
102 | 
103 | An array of elements with [optional end tags][html-syntax]. These end tags will be removed.
104 | 
105 | Example:
106 | 
107 | ~~~yaml
108 | compress_html:
109 |   endings: [p, li, td]
110 | ~~~
111 | 
112 | Use the shortcut `all` to remove all optional endings.
113 | 
114 | ~~~yaml
115 | compress_html:
116 |   endings: all
117 | ~~~
118 | 
119 | ### startings
120 | 
121 | An array of elements with [optional start tags][html-syntax]. These start tags will be removed.
122 | 
123 | Example:
124 | 
125 | ~~~yaml
126 | compress_html:
127 |   startings: [html, head, body]
128 | ~~~
129 | 
130 | ## profile
131 | 
132 | A boolean value to turn on the profile mode. If true, the layout creates a HTML table after the compressed content. The table contains the file size in bytes during the compressing steps.
133 | 
134 | ~~~yaml
135 | compress_html:
136 |   profile: true
137 | ~~~
138 | 
139 | The profile table provides attributes for styling and reading. The `id` ends with build’s timestamp to be unique enough.
140 | 
141 | ~~~html
142 | 
146 | ~~~
147 | 
148 | This page itself is compressed in profile mode for educational purposes only. The [table](#compress_html_profile_{{ site.time | date: "%Y%m%d" }}) is below. Please don’t profile in public.
149 | 
150 | ### ignore.envs
151 | 
152 | An array of environments given by `ENV["JEKYLL_ENV"]` where the compress layout is ignored. This may be useful while developing a website.
153 | 
154 | Use the shortcut `all` to disable compression in all environments.
155 | 
156 | ### blanklines
157 | 
158 | A boolean value to turn on blanklines mode. This mode will only remove lines consisting of whitespace and leave other lines alone.
159 | 
160 | ~~~yaml
161 | compress_html:
162 |   blanklines: true
163 | ~~~
164 | 
165 | 
166 | ### Full-blown sample
167 | 
168 | ~~~yaml
169 | compress_html:
170 |   clippings: all
171 |   comments: [""]
172 |   endings: all
173 |   ignore:
174 |     envs: [local]
175 |   blanklines: false
176 |   profile: true
177 |   startings: [html, head, body]
178 | ~~~
179 | 
180 | ## Restrictions
181 | 
182 | * Whitespaces inside of the `textarea` element are squeezed. Please don’t use the layout on pages with non-empty `textarea`.
183 | * Inline JS can become broken where `//` comments used. Please remove the comments or change to `/**/` style.
184 | * Invalid markup can lead to unexpected results. Please make sure your markup is valid before.
185 | 
186 | ## Examples
187 | 
188 | This page itself is compressed by the layout. It’s hosted by GitHub in the `gh-pages` [branch][github-repo-gh-pages].
189 | 
190 | Look how [others use][github-search] the layout on GitHub too.
191 | 
192 | ## Development
193 | 
194 | Feel free to submit bugs, patches, and questions in the [repository][github-repo].
195 | 
196 | Take a look at project’s `test/source` and `test/expected` directories. They contain self-explanatory specifications. Run `rake` to test the layout.
197 | 
198 | ## Reviews
199 | 
200 | * _[A pure Liquid way to compress HTML][hutchison-review]_ by David Hutchison
201 | * _[I am a Jekyll God][braithwaite-review]_ by Garth Braithwaite
202 | * _[Compressing HTML in Jekyll without a plugin][knight-review]_ by Rich Knight
203 | * _[Generating my static site with Jekyll and GitHub Pages][thorne-review]_ by Michael Thorne
204 | * _[99/100 Google Page Speed Score][steinbach-review]_ by James Steinbach
205 | 
206 | ----
207 | 
208 | © 2014–{{ site.time | date: "%Y" }} Anatol Broder. Released under the MIT License.
209 | 
210 | [jekyll]: https://jekyllrb.com/
211 | [html-spec]: https://html.spec.whatwg.org/multipage/
212 | [html-semantics]: https://html.spec.whatwg.org/multipage/semantics.html
213 | [html-syntax]: https://html.spec.whatwg.org/multipage/syntax.html
214 | [html-tabular]: https://html.spec.whatwg.org/multipage/tables.html
215 | [liquid]: https://docs.shopify.com/themes/liquid-documentation/basics
216 | [github-repo]: https://github.com/penibelst/jekyll-compress-html
217 | [github-repo-latest]: https://github.com/penibelst/jekyll-compress-html/releases/latest
218 | [github-repo-gh-pages]: https://github.com/penibelst/jekyll-compress-html/tree/gh-pages
219 | [github-search]: https://github.com/search?l=html&o=desc&q=filename%3Acompress.html+penibelst+compress_html&s=indexed&type=Code
220 | [cond]: https://msdn.microsoft.com/en-us/library/ms537512.aspx
221 | [hutchison-review]: https://www.devwithimagination.com/2014/06/12/jekyll-compress-a-pure-liquid-way-to-compress-html/
222 | [knight-review]: https://rich-knight.com/articles/compressing-html-in-jekyll/
223 | [braithwaite-review]: https://garthdb.com/writings/i-am-a-jekyll-god/
224 | [thorne-review]: https://www.userx.co.za/journal/generating-my-static-site-with-jekyll-and-github-pages/
225 | [steinbach-review]: https://jdsteinbach.com/performance/99-100-google-page-speed/
226 | 


--------------------------------------------------------------------------------
/site/ui/_scss/foundation/components/_grid.scss:
--------------------------------------------------------------------------------
  1 | // Foundation by ZURB
  2 | // foundation.zurb.com
  3 | // Licensed under MIT Open Source
  4 | 
  5 | @import "global";
  6 | 
  7 | //
  8 | // @variables
  9 | //
 10 | $include-html-grid-classes: $include-html-classes !default;
 11 | $include-xl-html-grid-classes: false !default;
 12 | 
 13 | $row-width: rem-calc(1000) !default;
 14 | $total-columns: 12 !default;
 15 | 
 16 | $last-child-float: $opposite-direction !default;
 17 | 
 18 | //
 19 | // Grid Functions
 20 | //
 21 | 
 22 | // Deprecated: We'll drop support for this in 5.1, use grid-calc()
 23 | @function gridCalc($colNumber, $totalColumns) {
 24 |   @warn "gridCalc() is deprecated, use grid-calc()";
 25 |   @return grid-calc($colNumber, $totalColumns);
 26 | }
 27 | 
 28 | // @FUNCTION
 29 | // $colNumber - Found in settings file
 30 | // $totalColumns - Found in settings file
 31 | @function grid-calc($colNumber, $totalColumns) {
 32 |   @return percentage(($colNumber / $totalColumns));
 33 | }
 34 | 
 35 | //
 36 | // @mixins
 37 | //
 38 | 
 39 | // For creating container, nested, and collapsed rows.
 40 | //
 41 | //
 42 | // $behavior - Any special behavior for this row? Default: false. Options: nest, collapse, nest-collapse, false.
 43 | @mixin grid-row($behavior: false) {
 44 | 
 45 |   // use @include grid-row(nest); to include a nested row
 46 |   @if $behavior == nest {
 47 |     width: auto;
 48 |     margin-#{$default-float}: -($column-gutter/2);
 49 |     margin-#{$opposite-direction}: -($column-gutter/2);
 50 |     margin-top: 0;
 51 |     margin-bottom: 0;
 52 |     max-width: none;
 53 |   }
 54 | 
 55 |   // use @include grid-row(collapse); to collapsed a container row margins
 56 |   @else if $behavior == collapse {
 57 |     width: 100%;
 58 |     margin: 0;
 59 |     max-width: $row-width;
 60 |   }
 61 | 
 62 |   // use @include grid-row(nest-collapse); to collapse outer margins on a nested row
 63 |   @else if $behavior == nest-collapse {
 64 |     width: auto;
 65 |     margin: 0;
 66 |     max-width: none;
 67 |   }
 68 | 
 69 |   // use @include grid-row; to use a container row
 70 |   @else {
 71 |     width: 100%;
 72 |     margin-#{$default-float}: auto;
 73 |     margin-#{$opposite-direction}: auto;
 74 |     margin-top: 0;
 75 |     margin-bottom: 0;
 76 |     max-width: $row-width;
 77 |   }
 78 | 
 79 |   // Clearfix for all rows
 80 |   @include clearfix();
 81 | }
 82 | 
 83 | // Creates a column, should be used inside of a media query to control layouts
 84 | //
 85 | // $columns - The number of columns this should be
 86 | // $last-column - Is this the last column? Default: false.
 87 | // $center - Center these columns? Default: false.
 88 | // $offset - # of columns to offset. Default: false.
 89 | // $push - # of columns to push. Default: false.
 90 | // $pull - # of columns to pull. Default: false.
 91 | // $collapse - Get rid of gutter padding on column? Default: false.
 92 | // $float - Should this float? Default: true. Options: true, false, left, right.
 93 | @mixin grid-column(
 94 |   $columns:false,
 95 |   $last-column:false,
 96 |   $center:false,
 97 |   $offset:false,
 98 |   $push:false,
 99 |   $pull:false,
100 |   $collapse:false,
101 |   $float:true,
102 |   $position:false) {
103 | 
104 |   // If positioned for default .column, include relative position
105 |   // push and pull require position set
106 |   @if $position or $push or $pull {
107 |     position: relative;
108 |   }
109 | 
110 |   // If collapsed, get rid of gutter padding
111 |   @if $collapse {
112 |     padding-left: 0;
113 |     padding-right: 0;
114 |   }
115 | 
116 |   // Gutter padding whenever a column isn't set to collapse
117 |   // (use $collapse:null to do nothing)
118 |   @else if $collapse == false {
119 |     padding-left: ($column-gutter / 2);
120 |     padding-right: ($column-gutter / 2);
121 |   }
122 | 
123 |   // If a column number is given, calculate width
124 |   @if $columns {
125 |     width: grid-calc($columns, $total-columns);
126 | 
127 |     // If last column, float naturally instead of to the right
128 |     @if $last-column { float: $opposite-direction; }
129 |   }
130 | 
131 |   // Source Ordering, adds left/right depending on which you use.
132 |   @if $push { #{$default-float}: grid-calc($push, $total-columns); #{$opposite-direction}: auto; }
133 |   @if $pull { #{$opposite-direction}: grid-calc($pull, $total-columns); #{$default-float}: auto; }
134 | 
135 |   @if $float {
136 |     @if $float == left or $float == true { float: $default-float; }
137 |     @else if $float == right { float: $opposite-direction; }
138 |     @else { float: none; }
139 |   }
140 | 
141 |   // If centered, get rid of float and add appropriate margins
142 |   @if $center {
143 |     margin-#{$default-float}: auto;
144 |     margin-#{$opposite-direction}: auto;
145 |     float: none;
146 |   }
147 | 
148 |   // If offset, calculate appropriate margins
149 |   @if $offset { margin-#{$default-float}: grid-calc($offset, $total-columns) !important; }
150 | 
151 | }
152 | 
153 | // Create presentational classes for grid
154 | //
155 | // $size - Name of class to use, i.e. "large" will generate .large-1, .large-2, etc.
156 | @mixin grid-html-classes($size) {
157 | 
158 |   @for $i from 0 through $total-columns - 1 {
159 |     .#{$size}-push-#{$i} {
160 |       @include grid-column($push:$i, $collapse:null, $float:false);
161 |     }
162 |     .#{$size}-pull-#{$i} {
163 |       @include grid-column($pull:$i, $collapse:null, $float:false);
164 |     }
165 |   }
166 | 
167 |   .column,
168 |   .columns { @include grid-column($columns:false, $position:true); }
169 | 
170 | 
171 |   @for $i from 1 through $total-columns {
172 |     .#{$size}-#{$i} { @include grid-column($columns:$i,$collapse:null,$float:false); }
173 |   }
174 | 
175 |   @for $i from 0 through $total-columns - 1 {
176 |     .#{$size}-offset-#{$i} { @include grid-column($offset:$i, $collapse:null,$float:false); }
177 |   }
178 | 
179 |   .#{$size}-reset-order {
180 |     margin-#{$default-float}: 0;
181 |     margin-#{$opposite-direction}: 0;
182 |     left: auto;
183 |     right: auto;
184 |     float: $default-float;
185 |   }
186 | 
187 |   .column.#{$size}-centered,
188 |   .columns.#{$size}-centered { @include grid-column($center:true, $collapse:null, $float:false); }
189 | 
190 |   .column.#{$size}-uncentered,
191 |   .columns.#{$size}-uncentered {
192 |     margin-#{$default-float}: 0;
193 |     margin-#{$opposite-direction}: 0;
194 |     float: $default-float;
195 |   }
196 | 
197 |   // Fighting [class*="column"] + [class*="column"]:last-child
198 |   .column.#{$size}-centered:last-child,
199 |   .columns.#{$size}-centered:last-child{
200 |     float: none;
201 |   }
202 | 
203 |   // Fighting .column.-centered:last-child
204 |   .column.#{$size}-uncentered:last-child,
205 |   .columns.#{$size}-uncentered:last-child {
206 |     float: $default-float;
207 |   }
208 | 
209 |   .column.#{$size}-uncentered.opposite,
210 |   .columns.#{$size}-uncentered.opposite {
211 |     float: $opposite-direction;
212 |   }
213 | 
214 | 	.row {
215 | 		&.#{$size}-collapse {
216 | 			> .column,
217 | 			> .columns { @include grid-column($collapse:true, $float:false); }
218 | 
219 | 			.row {margin-left:0; margin-right:0;}
220 | 		}
221 | 		&.#{$size}-uncollapse {
222 | 			> .column,
223 | 			> .columns {
224 | 				@include grid-column;
225 | 			}
226 | 		}
227 | 	}
228 | }
229 | 
230 | @include exports("grid") {
231 |   @if $include-html-grid-classes {
232 |     .row {
233 |       @include grid-row;
234 | 
235 |       &.collapse {
236 |          > .column,
237 |          > .columns { @include grid-column($collapse:true, $float:false); }
238 | 
239 |         .row {margin-left:0; margin-right:0;}
240 |       }
241 | 
242 |       .row { @include grid-row($behavior:nest);
243 |         &.collapse { @include grid-row($behavior:nest-collapse); }
244 |       }
245 |     }
246 | 
247 |     .column,
248 |     .columns { @include grid-column($columns:$total-columns); }
249 | 
250 |     [class*="column"] + [class*="column"]:last-child { float: $last-child-float; }
251 |     [class*="column"] + [class*="column"].end { float: $default-float; }
252 | 
253 |     @media #{$small-up} {
254 |       @include grid-html-classes($size:small);
255 |     }
256 | 
257 |     @media #{$medium-up} {
258 |       @include grid-html-classes($size:medium);
259 |       // Old push and pull classes
260 |       @for $i from 0 through $total-columns - 1 {
261 |         .push-#{$i} {
262 |           @include grid-column($push:$i, $collapse:null, $float:false);
263 |         }
264 |         .pull-#{$i} {
265 |           @include grid-column($pull:$i, $collapse:null, $float:false);
266 |         }
267 |       }
268 |     }
269 |     @media #{$large-up} {
270 |       @include grid-html-classes($size:large);
271 |       @for $i from 0 through $total-columns - 1 {
272 |         .push-#{$i} {
273 |           @include grid-column($push:$i, $collapse:null, $float:false);
274 |         }
275 |         .pull-#{$i} {
276 |           @include grid-column($pull:$i, $collapse:null, $float:false);
277 |         }
278 |       }
279 |     }
280 |   }
281 |   @if $include-xl-html-grid-classes {
282 |     @media #{$xlarge-up} {
283 |       @include grid-html-classes($size:xlarge);
284 |     }
285 |     @media #{$xxlarge-up} {
286 |       @include grid-html-classes($size:xxlarge);
287 |     }
288 |   }
289 | }
290 | 


--------------------------------------------------------------------------------
/site/ui/_scss/_normalize.scss:
--------------------------------------------------------------------------------
  1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */
  2 | 
  3 | /**
  4 |  * 1. Set default font family to sans-serif.
  5 |  * 2. Prevent iOS text size adjust after orientation change, without disabling
  6 |  *    user zoom.
  7 |  */
  8 | 
  9 | html {
 10 |   font-family: sans-serif; /* 1 */
 11 |   -ms-text-size-adjust: 100%; /* 2 */
 12 |   -webkit-text-size-adjust: 100%; /* 2 */
 13 | }
 14 | 
 15 | /**
 16 |  * Remove default margin.
 17 |  */
 18 | 
 19 | body {
 20 |   margin: 0;
 21 | }
 22 | 
 23 | /* HTML5 display definitions
 24 |    ========================================================================== */
 25 | 
 26 | /**
 27 |  * Correct `block` display not defined for any HTML5 element in IE 8/9.
 28 |  * Correct `block` display not defined for `details` or `summary` in IE 10/11
 29 |  * and Firefox.
 30 |  * Correct `block` display not defined for `main` in IE 11.
 31 |  */
 32 | 
 33 | article,
 34 | aside,
 35 | details,
 36 | figcaption,
 37 | figure,
 38 | footer,
 39 | header,
 40 | hgroup,
 41 | main,
 42 | menu,
 43 | nav,
 44 | section,
 45 | summary {
 46 |   display: block;
 47 | }
 48 | 
 49 | /**
 50 |  * 1. Correct `inline-block` display not defined in IE 8/9.
 51 |  * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
 52 |  */
 53 | 
 54 | audio,
 55 | canvas,
 56 | progress,
 57 | video {
 58 |   display: inline-block; /* 1 */
 59 |   vertical-align: baseline; /* 2 */
 60 | }
 61 | 
 62 | /**
 63 |  * Prevent modern browsers from displaying `audio` without controls.
 64 |  * Remove excess height in iOS 5 devices.
 65 |  */
 66 | 
 67 | audio:not([controls]) {
 68 |   display: none;
 69 |   height: 0;
 70 | }
 71 | 
 72 | /**
 73 |  * Address `[hidden]` styling not present in IE 8/9/10.
 74 |  * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
 75 |  */
 76 | 
 77 | [hidden],
 78 | template {
 79 |   display: none;
 80 | }
 81 | 
 82 | /* Links
 83 |    ========================================================================== */
 84 | 
 85 | /**
 86 |  * Remove the gray background color from active links in IE 10.
 87 |  */
 88 | 
 89 | a {
 90 |   background-color: transparent;
 91 | }
 92 | 
 93 | /**
 94 |  * Improve readability when focused and also mouse hovered in all browsers.
 95 |  */
 96 | 
 97 | a:active,
 98 | a:hover {
 99 |   outline: 0;
100 | }
101 | 
102 | /* Text-level semantics
103 |    ========================================================================== */
104 | 
105 | /**
106 |  * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
107 |  */
108 | 
109 | abbr[title] {
110 |   border-bottom: 1px dotted;
111 | }
112 | 
113 | /**
114 |  * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
115 |  */
116 | 
117 | b,
118 | strong {
119 |   font-weight: bold;
120 | }
121 | 
122 | /**
123 |  * Address styling not present in Safari and Chrome.
124 |  */
125 | 
126 | dfn {
127 |   font-style: italic;
128 | }
129 | 
130 | /**
131 |  * Address variable `h1` font-size and margin within `section` and `article`
132 |  * contexts in Firefox 4+, Safari, and Chrome.
133 |  */
134 | 
135 | h1 {
136 |   font-size: 2em;
137 |   margin: 0.67em 0;
138 | }
139 | 
140 | /**
141 |  * Address styling not present in IE 8/9.
142 |  */
143 | 
144 | mark {
145 |   background: #ff0;
146 |   color: #000;
147 | }
148 | 
149 | /**
150 |  * Address inconsistent and variable font size in all browsers.
151 |  */
152 | 
153 | small {
154 |   font-size: 80%;
155 | }
156 | 
157 | /**
158 |  * Prevent `sub` and `sup` affecting `line-height` in all browsers.
159 |  */
160 | 
161 | sub,
162 | sup {
163 |   font-size: 75%;
164 |   line-height: 0;
165 |   position: relative;
166 |   vertical-align: baseline;
167 | }
168 | 
169 | sup {
170 |   top: -0.5em;
171 | }
172 | 
173 | sub {
174 |   bottom: -0.25em;
175 | }
176 | 
177 | /* Embedded content
178 |    ========================================================================== */
179 | 
180 | /**
181 |  * Remove border when inside `a` element in IE 8/9/10.
182 |  */
183 | 
184 | img {
185 |   border: 0;
186 | }
187 | 
188 | /**
189 |  * Correct overflow not hidden in IE 9/10/11.
190 |  */
191 | 
192 | svg:not(:root) {
193 |   overflow: hidden;
194 | }
195 | 
196 | /* Grouping content
197 |    ========================================================================== */
198 | 
199 | /**
200 |  * Address margin not present in IE 8/9 and Safari.
201 |  */
202 | 
203 | figure {
204 |   margin: 1em 40px;
205 | }
206 | 
207 | /**
208 |  * Address differences between Firefox and other browsers.
209 |  */
210 | 
211 | hr {
212 |   -moz-box-sizing: content-box;
213 |   box-sizing: content-box;
214 |   height: 0;
215 | }
216 | 
217 | /**
218 |  * Contain overflow in all browsers.
219 |  */
220 | 
221 | pre {
222 |   overflow: auto;
223 | }
224 | 
225 | /**
226 |  * Address odd `em`-unit font size rendering in all browsers.
227 |  */
228 | 
229 | code,
230 | kbd,
231 | pre,
232 | samp {
233 |   font-family: monospace, monospace;
234 |   font-size: 1em;
235 | }
236 | 
237 | /* Forms
238 |    ========================================================================== */
239 | 
240 | /**
241 |  * Known limitation: by default, Chrome and Safari on OS X allow very limited
242 |  * styling of `select`, unless a `border` property is set.
243 |  */
244 | 
245 | /**
246 |  * 1. Correct color not being inherited.
247 |  *    Known issue: affects color of disabled elements.
248 |  * 2. Correct font properties not being inherited.
249 |  * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
250 |  */
251 | 
252 | button,
253 | input,
254 | optgroup,
255 | select,
256 | textarea {
257 |   color: inherit; /* 1 */
258 |   font: inherit; /* 2 */
259 |   margin: 0; /* 3 */
260 | }
261 | 
262 | /**
263 |  * Address `overflow` set to `hidden` in IE 8/9/10/11.
264 |  */
265 | 
266 | button {
267 |   overflow: visible;
268 | }
269 | 
270 | /**
271 |  * Address inconsistent `text-transform` inheritance for `button` and `select`.
272 |  * All other form control elements do not inherit `text-transform` values.
273 |  * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
274 |  * Correct `select` style inheritance in Firefox.
275 |  */
276 | 
277 | button,
278 | select {
279 |   text-transform: none;
280 | }
281 | 
282 | /**
283 |  * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
284 |  *    and `video` controls.
285 |  * 2. Correct inability to style clickable `input` types in iOS.
286 |  * 3. Improve usability and consistency of cursor style between image-type
287 |  *    `input` and others.
288 |  */
289 | 
290 | button,
291 | html input[type="button"], /* 1 */
292 | input[type="reset"],
293 | input[type="submit"] {
294 |   -webkit-appearance: button; /* 2 */
295 |   cursor: pointer; /* 3 */
296 | }
297 | 
298 | /**
299 |  * Re-set default cursor for disabled elements.
300 |  */
301 | 
302 | button[disabled],
303 | html input[disabled] {
304 |   cursor: default;
305 | }
306 | 
307 | /**
308 |  * Remove inner padding and border in Firefox 4+.
309 |  */
310 | 
311 | button::-moz-focus-inner,
312 | input::-moz-focus-inner {
313 |   border: 0;
314 |   padding: 0;
315 | }
316 | 
317 | /**
318 |  * Address Firefox 4+ setting `line-height` on `input` using `!important` in
319 |  * the UA stylesheet.
320 |  */
321 | 
322 | input {
323 |   line-height: normal;
324 | }
325 | 
326 | /**
327 |  * It's recommended that you don't attempt to style these elements.
328 |  * Firefox's implementation doesn't respect box-sizing, padding, or width.
329 |  *
330 |  * 1. Address box sizing set to `content-box` in IE 8/9/10.
331 |  * 2. Remove excess padding in IE 8/9/10.
332 |  */
333 | 
334 | input[type="checkbox"],
335 | input[type="radio"] {
336 |   box-sizing: border-box; /* 1 */
337 |   padding: 0; /* 2 */
338 | }
339 | 
340 | /**
341 |  * Fix the cursor style for Chrome's increment/decrement buttons. For certain
342 |  * `font-size` values of the `input`, it causes the cursor style of the
343 |  * decrement button to change from `default` to `text`.
344 |  */
345 | 
346 | input[type="number"]::-webkit-inner-spin-button,
347 | input[type="number"]::-webkit-outer-spin-button {
348 |   height: auto;
349 | }
350 | 
351 | /**
352 |  * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
353 |  * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
354 |  *    (include `-moz` to future-proof).
355 |  */
356 | 
357 | input[type="search"] {
358 |   -webkit-appearance: textfield; /* 1 */
359 |   -moz-box-sizing: content-box;
360 |   -webkit-box-sizing: content-box; /* 2 */
361 |   box-sizing: content-box;
362 | }
363 | 
364 | /**
365 |  * Remove inner padding and search cancel button in Safari and Chrome on OS X.
366 |  * Safari (but not Chrome) clips the cancel button when the search input has
367 |  * padding (and `textfield` appearance).
368 |  */
369 | 
370 | input[type="search"]::-webkit-search-cancel-button,
371 | input[type="search"]::-webkit-search-decoration {
372 |   -webkit-appearance: none;
373 | }
374 | 
375 | /**
376 |  * Define consistent border, margin, and padding.
377 |  */
378 | 
379 | fieldset {
380 |   border: 1px solid #c0c0c0;
381 |   margin: 0 2px;
382 |   padding: 0.35em 0.625em 0.75em;
383 | }
384 | 
385 | /**
386 |  * 1. Correct `color` not being inherited in IE 8/9/10/11.
387 |  * 2. Remove padding so people aren't caught out if they zero out fieldsets.
388 |  */
389 | 
390 | legend {
391 |   border: 0; /* 1 */
392 |   padding: 0; /* 2 */
393 | }
394 | 
395 | /**
396 |  * Remove default vertical scrollbar in IE 8/9/10/11.
397 |  */
398 | 
399 | textarea {
400 |   overflow: auto;
401 | }
402 | 
403 | /**
404 |  * Don't inherit the `font-weight` (applied by a rule above).
405 |  * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
406 |  */
407 | 
408 | optgroup {
409 |   font-weight: bold;
410 | }
411 | 
412 | /* Tables
413 |    ========================================================================== */
414 | 
415 | /**
416 |  * Remove most spacing between table cells.
417 |  */
418 | 
419 | table {
420 |   border-collapse: collapse;
421 |   border-spacing: 0;
422 | }
423 | 
424 | td,
425 | th {
426 |   padding: 0;
427 | }
428 | 


--------------------------------------------------------------------------------
/site/ui/_scss/foundation/components/_global.scss:
--------------------------------------------------------------------------------
  1 | // Foundation by ZURB
  2 | // foundation.zurb.com
  3 | // Licensed under MIT Open Source
  4 | 
  5 | @import "../functions";
  6 | //
  7 | // Foundation Variables
  8 | //
  9 | 
 10 | // Data attribute namespace
 11 | // styles get applied to [data-mysite-plugin], etc
 12 | $namespace: false !default;
 13 | 
 14 | // The default font-size is set to 100% of the browser style sheet (usually 16px)
 15 | // for compatibility with browser-based text zoom or user-set defaults.
 16 | 
 17 | // Since the typical default browser font-size is 16px, that makes the calculation for grid size.
 18 | // If you want your base font-size to be different and not have it affect the grid breakpoints,
 19 | // set $rem-base to $base-font-size and make sure $base-font-size is a px value.
 20 | $base-font-size: 100% !default;
 21 | 
 22 | // $base-line-height is 24px while $base-font-size is 16px
 23 | $base-line-height: 1.5 !default;
 24 | 
 25 | //
 26 | // Global Foundation Mixins
 27 | //
 28 | 
 29 | // @mixins
 30 | //
 31 | // We use this to control border radius.
 32 | // $radius - Default: $global-radius || 4px
 33 | @mixin radius($radius:$global-radius) {
 34 |   @if $radius {
 35 |     border-radius: $radius;
 36 |   }
 37 | }
 38 | 
 39 | // @mixins
 40 | //
 41 | // We use this to create equal side border radius on elements.
 42 | // $side - Options: left, right, top, bottom
 43 | @mixin side-radius($side, $radius:$global-radius) {
 44 |   @if ($side == left or $side == right) {
 45 |     -webkit-border-bottom-#{$side}-radius: $radius;
 46 |     -webkit-border-top-#{$side}-radius: $radius;
 47 |     border-bottom-#{$side}-radius: $radius;
 48 |     border-top-#{$side}-radius: $radius;
 49 |   } @else {
 50 |     -webkit-#{$side}-left-radius: $radius;
 51 |     -webkit-#{$side}-right-radius: $radius;
 52 |     border-#{$side}-left-radius: $radius;
 53 |     border-#{$side}-right-radius: $radius;
 54 |   }
 55 | }
 56 | 
 57 | // @mixins
 58 | //
 59 | // We can control whether or not we have inset shadows edges.
 60 | // $active - Default: true, Options: false
 61 | @mixin inset-shadow($active:true) {
 62 |   box-shadow: $shiny-edge-size $shiny-edge-color inset;
 63 | 
 64 |   @if $active { &:active {
 65 |     box-shadow: $shiny-edge-size $shiny-edge-active-color inset; } }
 66 | }
 67 | 
 68 | // @mixins
 69 | //
 70 | // We use this to add transitions to elements
 71 | // $property - Default: all, Options: http://www.w3.org/TR/css3-transitions/#animatable-properties
 72 | // $speed - Default: 300ms
 73 | // $ease - Default:ease-out, Options: http://css-tricks.com/almanac/properties/t/transition-timing-function/
 74 | @mixin single-transition($property:all, $speed:300ms, $ease:ease-out) {
 75 |   transition: $property $speed $ease;
 76 | }
 77 | 
 78 | // @mixins
 79 | //
 80 | // We use this to add box-sizing across browser prefixes
 81 | @mixin box-sizing($type:border-box) {
 82 |   -webkit-box-sizing: $type; // Android < 2.3, iOS < 4
 83 |      -moz-box-sizing: $type; // Firefox < 29
 84 |           box-sizing: $type; // Chrome, IE 8+, Opera, Safari 5.1
 85 | }
 86 | 
 87 | // @mixins
 88 | //
 89 | // We use this to create isosceles triangles
 90 | // $triangle-size - Used to set border-size. No default, set a px or em size.
 91 | // $triangle-color - Used to set border-color which makes up triangle. No default
 92 | // $triangle-direction - Used to determine which direction triangle points. Options: top, bottom, left, right
 93 | @mixin css-triangle($triangle-size, $triangle-color, $triangle-direction) {
 94 |   content: "";
 95 |   display: block;
 96 |   width: 0;
 97 |   height: 0;
 98 |   border: inset $triangle-size;
 99 |   @if ($triangle-direction == top) {
100 |     border-color: $triangle-color transparent transparent transparent;
101 |     border-top-style: solid;
102 |   }
103 |   @if ($triangle-direction == bottom) {
104 |     border-color: transparent transparent $triangle-color transparent;
105 |     border-bottom-style: solid;
106 |   }
107 |   @if ($triangle-direction == left) {
108 |     border-color: transparent transparent transparent $triangle-color;
109 |     border-left-style: solid;
110 |   }
111 |   @if ($triangle-direction == right) {
112 |     border-color: transparent $triangle-color transparent transparent;
113 |     border-right-style: solid;
114 |   }
115 | }
116 | 
117 | // @mixins
118 | //
119 | // We use this to create the icon with three lines aka the hamburger icon, the menu-icon or the navicon
120 | // $width - Width of hamburger icon in rem
121 | // $left - If false, icon will be centered horizontally || explicitly set value in rem
122 | // $top - If false, icon will be centered vertically || explicitly set value in rem
123 | // $thickness - thickness of lines in hamburger icon, set value in px
124 | // $gap - spacing between the lines in hamburger icon, set value in px
125 | // $color - icon color
126 | // $hover-color - icon color during hover
127 | // $offcanvas - Set to true of @include in offcanvas
128 | @mixin hamburger($width, $left, $top, $thickness, $gap, $color, $hover-color, $offcanvas) {
129 |   span::after {
130 |     content: "";
131 |     position: absolute;
132 |     display: block;
133 |     height: 0;
134 | 
135 |     @if $offcanvas {
136 |       @if $top {
137 |         top: $top;
138 |       }
139 |       @else {
140 |         top: 50%;
141 |         margin-top: (-$width/2);
142 |       }
143 |       @if $left {
144 |         left: $left;
145 |       }
146 |       @else {
147 |         left: ($tabbar-menu-icon-width - $width)/2;
148 |       }
149 |     }
150 |     @else {
151 |       top: 50%;
152 |       margin-top: -($width/2);
153 |       #{$opposite-direction}: $topbar-link-padding;
154 |     }
155 | 
156 |     box-shadow:
157 |       0 0 0 $thickness $color,
158 |       0 $gap + $thickness 0 $thickness $color,
159 |       0 (2 * $gap + 2*$thickness) 0 $thickness $color;
160 |     width: $width;
161 |   }
162 |   span:hover:after {
163 |     box-shadow:
164 |       0 0 0 $thickness $hover-color,
165 |       0 $gap + $thickness 0 $thickness $hover-color,
166 |       0 (2 * $gap + 2*$thickness) 0 $thickness $hover-color;
167 |   }
168 | }
169 | 
170 | // We use this to do clear floats
171 | @mixin clearfix {
172 |   &:before, &:after { content: " "; display: table; }
173 |   &:after { clear: both; }
174 | }
175 | 
176 | // @mixins
177 | //
178 | // We use this to add a glowing effect to block elements
179 | // $selector - Used for selector state. Default: focus, Options: hover, active, visited
180 | // $fade-time - Default: 300ms
181 | // $glowing-effect-color - Default: fade-out($primary-color, .25)
182 | @mixin block-glowing-effect($selector:focus, $fade-time:300ms, $glowing-effect-color:fade-out($primary-color, .25)) {
183 |   transition: box-shadow $fade-time, border-color $fade-time ease-in-out;
184 | 
185 |   &:#{$selector} {
186 |     box-shadow: 0 0 5px $glowing-effect-color;
187 |     border-color: $glowing-effect-color;
188 |   }
189 | }
190 | 
191 | // @mixins
192 | //
193 | // We use this to translate elements in 2D
194 | // $horizontal: Default: 0
195 | // $vertical: Default: 0
196 | @mixin translate2d($horizontal:0, $vertical:0) {
197 |   transform: translate($horizontal,$vertical)
198 | }
199 | 
200 | // @mixins
201 | //
202 | // Makes an element visually hidden, but accessible.
203 | // @see http://snook.ca/archives/html_and_css/hiding-content-for-accessibility
204 | @mixin element-invisible {
205 |   position: absolute !important;
206 |   height: 1px;
207 |   width: 1px;
208 |   overflow: hidden;
209 |   clip: rect(1px, 1px, 1px, 1px);
210 | }
211 | 
212 | // @mixins
213 | //
214 | // Turns off the element-invisible effect.
215 | @mixin element-invisible-off {
216 |   position: static !important;
217 |   height: auto;
218 |   width: auto;
219 |   overflow: visible;
220 |   clip: auto;
221 | }
222 | 
223 | $white         : #FFFFFF !default;
224 | $ghost         : #FAFAFA !default;
225 | $snow          : #F9F9F9 !default;
226 | $vapor         : #F6F6F6 !default;
227 | $white-smoke   : #F5F5F5 !default;
228 | $silver        : #EFEFEF !default;
229 | $smoke         : #EEEEEE !default;
230 | $gainsboro     : #DDDDDD !default;
231 | $iron          : #CCCCCC !default;
232 | $base          : #AAAAAA !default;
233 | $aluminum      : #999999 !default;
234 | $jumbo         : #888888 !default;
235 | $monsoon       : #777777 !default;
236 | $steel         : #666666 !default;
237 | $charcoal      : #555555 !default;
238 | $tuatara       : #444444 !default;
239 | $oil           : #333333 !default;
240 | $jet           : #222222 !default;
241 | $black         : #000000 !default;
242 | 
243 | // We use these as default colors throughout
244 | $primary-color: #008CBA !default;   // bondi-blue
245 | $secondary-color: #e7e7e7 !default; // white-lilac
246 | $alert-color: #f04124 !default;     // cinnabar
247 | $success-color: #43AC6A !default;   // sea-green
248 | $warning-color: #f08a24 !default;   // carrot
249 | $info-color: #a0d3e8 !default;      // cornflower
250 | 
251 | // We use these to define default font stacks
252 | $font-family-sans-serif: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif !default;
253 | $font-family-serif: Georgia, Cambria, "Times New Roman", Times, serif !default;
254 | $font-family-monospace: Consolas, "Liberation Mono", Courier, monospace !default;
255 | 
256 | // We use these to define default font weights
257 | $font-weight-normal: normal !default;
258 | $font-weight-bold: bold !default;
259 | 
260 | // We use these to control various global styles
261 | $body-bg: #fff !default;
262 | $body-font-color: #222 !default;
263 | $body-font-family: $font-family-sans-serif !default;
264 | $body-font-weight: $font-weight-normal !default;
265 | $body-font-style: normal !default;
266 | 
267 | // We use this to control font-smoothing
268 | $font-smoothing: antialiased !default;
269 | 
270 | // We use these to control text direction settings
271 | $text-direction: ltr !default;
272 | $default-float: left !default;
273 | $opposite-direction: right !default;
274 | @if $text-direction == ltr {
275 |   $default-float: left;
276 |   $opposite-direction: right;
277 | } @else {
278 |   $default-float: right;
279 |   $opposite-direction: left;
280 | }
281 | 
282 | // We use these to make sure border radius matches unless we want it different.
283 | $global-radius: 3px !default;
284 | $global-rounded: 1000px !default;
285 | 
286 | // We use these to control inset shadow shiny edges and depressions.
287 | $shiny-edge-size: 0 1px 0 !default;
288 | $shiny-edge-color: rgba(#fff, .5) !default;
289 | $shiny-edge-active-color: rgba(#000, .2) !default;
290 | 
291 | // We use this to control whether or not CSS classes come through in the gem files.
292 | $include-html-classes: true !default;
293 | $include-print-styles: true !default;
294 | $include-html-global-classes: $include-html-classes !default;
295 | 
296 | $column-gutter: rem-calc(30) !default;
297 | 
298 | // Media Query Ranges
299 | $small-range: (0, 40em) !default;
300 | $medium-range: (40.063em, 64em) !default;
301 | $large-range: (64.063em, 90em) !default;
302 | $xlarge-range: (90.063em, 120em) !default;
303 | $xxlarge-range: (120.063em, 99999999em) !default;
304 | 
305 | 
306 | $screen: "only screen" !default;
307 | 
308 | $landscape: "#{$screen} and (orientation: landscape)" !default;
309 | $portrait: "#{$screen} and (orientation: portrait)" !default;
310 | 
311 | $small-up: $screen !default;
312 | $small-only: "#{$screen} and (max-width: #{upper-bound($small-range)})" !default;
313 | 
314 | $medium-up: "#{$screen} and (min-width:#{lower-bound($medium-range)})" !default;
315 | $medium-only: "#{$screen} and (min-width:#{lower-bound($medium-range)}) and (max-width:#{upper-bound($medium-range)})" !default;
316 | 
317 | $large-up: "#{$screen} and (min-width:#{lower-bound($large-range)})" !default;
318 | $large-only: "#{$screen} and (min-width:#{lower-bound($large-range)}) and (max-width:#{upper-bound($large-range)})" !default;
319 | 
320 | $xlarge-up: "#{$screen} and (min-width:#{lower-bound($xlarge-range)})" !default;
321 | $xlarge-only: "#{$screen} and (min-width:#{lower-bound($xlarge-range)}) and (max-width:#{upper-bound($xlarge-range)})" !default;
322 | 
323 | $xxlarge-up: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)})" !default;
324 | $xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (max-width:#{upper-bound($xxlarge-range)})" !default;
325 | 
326 | // Legacy
327 | $small: $medium-up;
328 | $medium: $medium-up;
329 | $large: $large-up;
330 | 
331 | 
332 | //We use this as cursors values for enabling the option of having custom cursors in the whole site's stylesheet
333 | $cursor-auto-value: auto !default;
334 | $cursor-crosshair-value: crosshair !default;
335 | $cursor-default-value: default !default;
336 | $cursor-pointer-value: pointer !default;
337 | $cursor-help-value: help !default;
338 | $cursor-text-value: text !default;
339 | 
340 | 
341 | @include exports("global") {
342 | 
343 |   // Meta styles are included in all builds, as they are a dependancy of the Javascript.
344 |   // Used to provide media query values for javascript components.
345 |   // Forward slash placed around everything to convince PhantomJS to read the value.
346 | 
347 |   meta.foundation-version {
348 |     font-family: "/5.5.0/";
349 |   }
350 | 
351 |   meta.foundation-mq-small {
352 |     font-family: "/" + unquote($small-up) + "/";
353 |     width: lower-bound($small-range);
354 |   }
355 | 
356 |   meta.foundation-mq-small-only {
357 |     font-family: "/" + unquote($small-only) + "/";
358 |     width: lower-bound($small-range);
359 |   }
360 | 
361 |   meta.foundation-mq-medium {
362 |     font-family: "/" + unquote($medium-up) + "/";
363 |     width: lower-bound($medium-range);
364 |   }
365 | 
366 |   meta.foundation-mq-medium-only {
367 |     font-family: "/" + unquote($medium-only) + "/";
368 |     width: lower-bound($medium-range);
369 |   }
370 | 
371 |   meta.foundation-mq-large {
372 |     font-family: "/" + unquote($large-up) + "/";
373 |     width: lower-bound($large-range);
374 |   }
375 | 
376 |   meta.foundation-mq-large-only {
377 |     font-family: "/" + unquote($large-only) + "/";
378 |     width: lower-bound($large-range);
379 |   }
380 | 
381 |   meta.foundation-mq-xlarge {
382 |     font-family: "/" + unquote($xlarge-up) + "/";
383 |     width: lower-bound($xlarge-range);
384 |   }
385 | 
386 |   meta.foundation-mq-xlarge-only {
387 |     font-family: "/" + unquote($xlarge-only) + "/";
388 |     width: lower-bound($xlarge-range);
389 |   }
390 | 
391 |   meta.foundation-mq-xxlarge {
392 |     font-family: "/" + unquote($xxlarge-up) + "/";
393 |     width: lower-bound($xxlarge-range);
394 |   }
395 | 
396 |   meta.foundation-data-attribute-namespace {
397 |     font-family: #{$namespace};
398 |   }
399 | 
400 |   @if $include-html-global-classes {
401 | 
402 |     // Must be 100% for off canvas to work
403 |     html, body { height: 100%; }
404 | 
405 |     // Set box-sizing globally to handle padding and border widths
406 |     *,
407 |     *:before,
408 |     *:after {
409 |       @include box-sizing(border-box);
410 |     }
411 | 
412 |     html,
413 |     body { font-size: $base-font-size; }
414 | 
415 |     // Default body styles
416 |     body {
417 |       background: $body-bg;
418 |       color: $body-font-color;
419 |       padding: 0;
420 |       margin: 0;
421 |       font-family: $body-font-family;
422 |       font-weight: $body-font-weight;
423 |       font-style: $body-font-style;
424 |       line-height: $base-line-height; // Set to $base-line-height to take on browser default of 150%
425 |       position: relative;
426 |       cursor: $cursor-auto-value;
427 |     }
428 | 
429 |   a:hover { cursor: $cursor-pointer-value; }
430 | 
431 |     // Grid Defaults to get images and embeds to work properly
432 |     img { max-width: 100%; height: auto; }
433 | 
434 |     img { -ms-interpolation-mode: bicubic; }
435 | 
436 |     #map_canvas,
437 |     .map_canvas {
438 |       img,
439 |       embed,
440 |       object { max-width: none !important;
441 |       }
442 |     }
443 | 
444 |     // Miscellaneous useful HTML classes
445 |     .left { float: left !important; }
446 |     .right { float: right !important; }
447 |     .clearfix { @include clearfix; }
448 | 
449 |     // Hide visually and from screen readers
450 |     .hide {
451 |       display: none !important;
452 |       visibility: hidden;
453 |     }
454 | 
455 |     // Hide visually and from screen readers, but maintain layout
456 |     .invisible { visibility: hidden; }
457 | 
458 |     // Font smoothing
459 |     // Antialiased font smoothing works best for light text on a dark background.
460 |     // Apply to single elements instead of globally to body.
461 |     // Note this only applies to webkit-based desktop browsers and Firefox 25 (and later) on the Mac.
462 |     .antialiased { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
463 | 
464 |     // Get rid of gap under images by making them display: inline-block; by default
465 |     img {
466 |       display: inline-block;
467 |       vertical-align: middle;
468 |     }
469 | 
470 |     //
471 |     // Global resets for forms
472 |     //
473 | 
474 |     // Make sure textarea takes on height automatically
475 |     textarea { height: auto; min-height: 50px; }
476 | 
477 |     // Make select elements 100% width by default
478 |     select { width: 100%; }
479 |   }
480 | }
481 | 


--------------------------------------------------------------------------------
/site/ui/_scss/foundation/components/_type.scss:
--------------------------------------------------------------------------------
  1 | // Foundation by ZURB
  2 | // foundation.zurb.com
  3 | // Licensed under MIT Open Source
  4 | 
  5 | @import "global";
  6 | 
  7 | $include-html-type-classes: $include-html-classes !default;
  8 | 
  9 | // We use these to control header font styles
 10 | $header-font-family: $body-font-family !default;
 11 | $header-font-weight: $font-weight-normal !default;
 12 | $header-font-style: $font-weight-normal !default;
 13 | $header-font-color: $jet !default;
 14 | $header-line-height: 1.4 !default;
 15 | $header-top-margin: .2rem !default;
 16 | $header-bottom-margin: .5rem !default;
 17 | $header-text-rendering: optimizeLegibility !default;
 18 | 
 19 | // We use these to control header font sizes
 20 | $h1-font-size: rem-calc(44) !default;
 21 | $h2-font-size: rem-calc(37) !default;
 22 | $h3-font-size: rem-calc(27) !default;
 23 | $h4-font-size: rem-calc(23) !default;
 24 | $h5-font-size: rem-calc(18) !default;
 25 | $h6-font-size: 1rem !default;
 26 | 
 27 | // We use these to control header size reduction on small screens
 28 | $h1-font-reduction: rem-calc(10) !default;
 29 | $h2-font-reduction: rem-calc(10) !default;
 30 | $h3-font-reduction: rem-calc(5) !default;
 31 | $h4-font-reduction: rem-calc(5) !default;
 32 | $h5-font-reduction: 0 !default;
 33 | $h6-font-reduction: 0 !default;
 34 | 
 35 | // These control how subheaders are styled.
 36 | $subheader-line-height: 1.4 !default;
 37 | $subheader-font-color: scale-color($header-font-color, $lightness: 35%) !default;
 38 | $subheader-font-weight: $font-weight-normal !default;
 39 | $subheader-top-margin: .2rem !default;
 40 | $subheader-bottom-margin: .5rem !default;
 41 | 
 42 | // A general  styling
 43 | $small-font-size: 60% !default;
 44 | $small-font-color: scale-color($header-font-color, $lightness: 35%) !default;
 45 | 
 46 | // We use these to style paragraphs
 47 | $paragraph-font-family: inherit !default;
 48 | $paragraph-font-weight: $font-weight-normal !default;
 49 | $paragraph-font-size: 1rem !default;
 50 | $paragraph-line-height: 1.6 !default;
 51 | $paragraph-margin-bottom: rem-calc(20) !default;
 52 | $paragraph-aside-font-size: rem-calc(14) !default;
 53 | $paragraph-aside-line-height: 1.35 !default;
 54 | $paragraph-aside-font-style: italic !default;
 55 | $paragraph-text-rendering: optimizeLegibility !default;
 56 | 
 57 | // We use these to style  tags
 58 | $code-color: $oil !default;
 59 | $code-font-family: $font-family-monospace !default;
 60 | $code-font-weight: $font-weight-normal !default;
 61 | $code-background-color: scale-color($secondary-color, $lightness: 70%) !default;
 62 | $code-border-size: 1px !default;
 63 | $code-border-style: solid !default;
 64 | $code-border-color: scale-color($code-background-color, $lightness: -10%) !default;
 65 | $code-padding: rem-calc(2) rem-calc(5) rem-calc(1) !default;
 66 | 
 67 | // We use these to style anchors
 68 | $anchor-text-decoration: none !default;
 69 | $anchor-text-decoration-hover: none !default;
 70 | $anchor-font-color: $primary-color !default;
 71 | $anchor-font-color-hover: scale-color($anchor-font-color, $lightness: -14%) !default;
 72 | 
 73 | // We use these to style the 
element 74 | $hr-border-width: 1px !default; 75 | $hr-border-style: solid !default; 76 | $hr-border-color: $gainsboro !default; 77 | $hr-margin: rem-calc(20) !default; 78 | 79 | // We use these to style lists 80 | $list-font-family: $paragraph-font-family !default; 81 | $list-font-size: $paragraph-font-size !default; 82 | $list-line-height: $paragraph-line-height !default; 83 | $list-margin-bottom: $paragraph-margin-bottom !default; 84 | $list-style-position: outside !default; 85 | $list-side-margin: 1.1rem !default; 86 | $list-ordered-side-margin: 1.4rem !default; 87 | $list-side-margin-no-bullet: 0 !default; 88 | $list-nested-margin: rem-calc(20) !default; 89 | $definition-list-header-weight: $font-weight-bold !default; 90 | $definition-list-header-margin-bottom: .3rem !default; 91 | $definition-list-margin-bottom: rem-calc(12) !default; 92 | 93 | // We use these to style blockquotes 94 | $blockquote-font-color: scale-color($header-font-color, $lightness: 35%) !default; 95 | $blockquote-padding: rem-calc(9 20 0 19) !default; 96 | $blockquote-border: 1px solid $gainsboro !default; 97 | $blockquote-cite-font-size: rem-calc(13) !default; 98 | $blockquote-cite-font-color: scale-color($header-font-color, $lightness: 23%) !default; 99 | $blockquote-cite-link-color: $blockquote-cite-font-color !default; 100 | 101 | // Acronym styles 102 | $acronym-underline: 1px dotted $gainsboro !default; 103 | 104 | // We use these to control padding and margin 105 | $microformat-padding: rem-calc(10 12) !default; 106 | $microformat-margin: rem-calc(0 0 20 0) !default; 107 | 108 | // We use these to control the border styles 109 | $microformat-border-width: 1px !default; 110 | $microformat-border-style: solid !default; 111 | $microformat-border-color: $gainsboro !default; 112 | 113 | // We use these to control full name font styles 114 | $microformat-fullname-font-weight: $font-weight-bold !default; 115 | $microformat-fullname-font-size: rem-calc(15) !default; 116 | 117 | // We use this to control the summary font styles 118 | $microformat-summary-font-weight: $font-weight-bold !default; 119 | 120 | // We use this to control abbr padding 121 | $microformat-abbr-padding: rem-calc(0 1) !default; 122 | 123 | // We use this to control abbr font styles 124 | $microformat-abbr-font-weight: $font-weight-bold !default; 125 | $microformat-abbr-font-decoration: none !default; 126 | 127 | // Text alignment class names 128 | $align-class-names: 129 | small-only, 130 | small, 131 | medium-only, 132 | medium, 133 | large-only, 134 | large, 135 | xlarge-only, 136 | xlarge, 137 | xxlarge-only, 138 | xxlarge; 139 | 140 | // Text alignment breakpoints 141 | $align-class-breakpoints: 142 | $small-only, 143 | $small-up, 144 | $medium-only, 145 | $medium-up, 146 | $large-only, 147 | $large-up, 148 | $xlarge-only, 149 | $xlarge-up, 150 | $xxlarge-only, 151 | $xxlarge-up; 152 | 153 | // Generates text align and justify classes 154 | @mixin align-classes{ 155 | .text-left { text-align: left !important; } 156 | .text-right { text-align: right !important; } 157 | .text-center { text-align: center !important; } 158 | .text-justify { text-align: justify !important; } 159 | 160 | @for $i from 1 through length($align-class-names) { 161 | @media #{(nth($align-class-breakpoints, $i))} { 162 | .#{(nth($align-class-names, $i))}-text-left { text-align: left !important; } 163 | .#{(nth($align-class-names, $i))}-text-right { text-align: right !important; } 164 | .#{(nth($align-class-names, $i))}-text-center { text-align: center !important; } 165 | .#{(nth($align-class-names, $i))}-text-justify { text-align: justify !important; } 166 | } 167 | } 168 | } 169 | 170 | // 171 | // Typography Placeholders 172 | // 173 | 174 | // These will throw a deprecation warning if used within a media query. 175 | @mixin lead { 176 | font-size: $paragraph-font-size + rem-calc(3.5); 177 | line-height: 1.6; 178 | } 179 | 180 | @mixin subheader { 181 | line-height: $subheader-line-height; 182 | color: $subheader-font-color; 183 | font-weight: $subheader-font-weight; 184 | margin-top: $subheader-top-margin; 185 | margin-bottom: $subheader-bottom-margin; 186 | } 187 | @include exports("type") { 188 | @if $include-html-type-classes { 189 | // Responsive Text alignment 190 | @include align-classes; 191 | 192 | /* Typography resets */ 193 | div, 194 | dl, 195 | dt, 196 | dd, 197 | ul, 198 | ol, 199 | li, 200 | h1, 201 | h2, 202 | h3, 203 | h4, 204 | h5, 205 | h6, 206 | pre, 207 | form, 208 | p, 209 | blockquote, 210 | th, 211 | td { 212 | margin:0; 213 | padding:0; 214 | } 215 | 216 | /* Default Link Styles */ 217 | a { 218 | color: $anchor-font-color; 219 | text-decoration: $anchor-text-decoration; 220 | line-height: inherit; 221 | 222 | &:hover, 223 | &:focus { 224 | color: $anchor-font-color-hover; 225 | @if $anchor-text-decoration-hover != $anchor-text-decoration { 226 | text-decoration: $anchor-text-decoration-hover; 227 | } 228 | } 229 | 230 | img { border:none; } 231 | } 232 | 233 | /* Default paragraph styles */ 234 | p { 235 | font-family: $paragraph-font-family; 236 | font-weight: $paragraph-font-weight; 237 | font-size: $paragraph-font-size; 238 | line-height: $paragraph-line-height; 239 | margin-bottom: $paragraph-margin-bottom; 240 | text-rendering: $paragraph-text-rendering; 241 | 242 | &.lead { @include lead; } 243 | 244 | & aside { 245 | font-size: $paragraph-aside-font-size; 246 | line-height: $paragraph-aside-line-height; 247 | font-style: $paragraph-aside-font-style; 248 | } 249 | } 250 | 251 | /* Default header styles */ 252 | h1, h2, h3, h4, h5, h6 { 253 | font-family: $header-font-family; 254 | font-weight: $header-font-weight; 255 | font-style: $header-font-style; 256 | color: $header-font-color; 257 | text-rendering: $header-text-rendering; 258 | margin-top: $header-top-margin; 259 | margin-bottom: $header-bottom-margin; 260 | line-height: $header-line-height; 261 | 262 | small { 263 | font-size: $small-font-size; 264 | color: $small-font-color; 265 | line-height: 0; 266 | } 267 | } 268 | 269 | h1 { font-size: $h1-font-size - $h1-font-reduction; } 270 | h2 { font-size: $h2-font-size - $h2-font-reduction; } 271 | h3 { font-size: $h3-font-size - $h3-font-reduction; } 272 | h4 { font-size: $h4-font-size - $h4-font-reduction; } 273 | h5 { font-size: $h5-font-size - $h5-font-reduction; } 274 | h6 { font-size: $h6-font-size - $h6-font-reduction; } 275 | 276 | .subheader { @include subheader; } 277 | 278 | hr { 279 | border: $hr-border-style $hr-border-color; 280 | border-width: $hr-border-width 0 0; 281 | clear: both; 282 | margin: $hr-margin 0 ($hr-margin - rem-calc($hr-border-width)); 283 | height: 0; 284 | } 285 | 286 | /* Helpful Typography Defaults */ 287 | em, 288 | i { 289 | font-style: italic; 290 | line-height: inherit; 291 | } 292 | 293 | strong, 294 | b { 295 | font-weight: $font-weight-bold; 296 | line-height: inherit; 297 | } 298 | 299 | small { 300 | font-size: $small-font-size; 301 | line-height: inherit; 302 | } 303 | 304 | code { 305 | font-family: $code-font-family; 306 | font-weight: $code-font-weight; 307 | color: $code-color; 308 | background-color: $code-background-color; 309 | border-width: $code-border-size; 310 | border-style: $code-border-style; 311 | border-color: $code-border-color; 312 | padding: $code-padding; 313 | } 314 | 315 | /* Lists */ 316 | ul, 317 | ol, 318 | dl { 319 | font-size: $list-font-size; 320 | line-height: $list-line-height; 321 | margin-bottom: $list-margin-bottom; 322 | list-style-position: $list-style-position; 323 | font-family: $list-font-family; 324 | } 325 | 326 | ul { 327 | margin-#{$default-float}: $list-side-margin; 328 | &.no-bullet { 329 | margin-#{$default-float}: $list-side-margin-no-bullet; 330 | li { 331 | ul, 332 | ol { 333 | margin-#{$default-float}: $list-nested-margin; 334 | margin-bottom: 0; 335 | list-style: none; 336 | } 337 | } 338 | } 339 | } 340 | 341 | /* Unordered Lists */ 342 | ul { 343 | li { 344 | ul, 345 | ol { 346 | margin-#{$default-float}: $list-nested-margin; 347 | margin-bottom: 0; 348 | } 349 | } 350 | &.square, 351 | &.circle, 352 | &.disc { 353 | li ul { list-style: inherit; } 354 | } 355 | 356 | &.square { list-style-type: square; margin-#{$default-float}: $list-side-margin;} 357 | &.circle { list-style-type: circle; margin-#{$default-float}: $list-side-margin;} 358 | &.disc { list-style-type: disc; margin-#{$default-float}: $list-side-margin;} 359 | &.no-bullet { list-style: none; } 360 | } 361 | 362 | /* Ordered Lists */ 363 | ol { 364 | margin-#{$default-float}: $list-ordered-side-margin; 365 | li { 366 | ul, 367 | ol { 368 | margin-#{$default-float}: $list-nested-margin; 369 | margin-bottom: 0; 370 | } 371 | } 372 | } 373 | 374 | /* Definition Lists */ 375 | dl { 376 | dt { 377 | margin-bottom: $definition-list-header-margin-bottom; 378 | font-weight: $definition-list-header-weight; 379 | } 380 | dd { margin-bottom: $definition-list-margin-bottom; } 381 | } 382 | 383 | /* Abbreviations */ 384 | abbr, 385 | acronym { 386 | text-transform: uppercase; 387 | font-size: 90%; 388 | color: $body-font-color; 389 | cursor: $cursor-help-value; 390 | } 391 | abbr { 392 | text-transform: none; 393 | &[title] { 394 | border-bottom: $acronym-underline; 395 | } 396 | } 397 | 398 | /* Blockquotes */ 399 | blockquote { 400 | margin: 0 0 $paragraph-margin-bottom; 401 | padding: $blockquote-padding; 402 | border-#{$default-float}: $blockquote-border; 403 | 404 | cite { 405 | display: block; 406 | font-size: $blockquote-cite-font-size; 407 | color: $blockquote-cite-font-color; 408 | &:before { 409 | content: "\2014 \0020"; 410 | } 411 | 412 | a, 413 | a:visited { 414 | color: $blockquote-cite-link-color; 415 | } 416 | } 417 | } 418 | blockquote, 419 | blockquote p { 420 | line-height: $paragraph-line-height; 421 | color: $blockquote-font-color; 422 | } 423 | 424 | /* Microformats */ 425 | .vcard { 426 | display: inline-block; 427 | margin: $microformat-margin; 428 | border: $microformat-border-width $microformat-border-style $microformat-border-color; 429 | padding: $microformat-padding; 430 | 431 | li { 432 | margin: 0; 433 | display: block; 434 | } 435 | .fn { 436 | font-weight: $microformat-fullname-font-weight; 437 | font-size: $microformat-fullname-font-size; 438 | } 439 | } 440 | 441 | .vevent { 442 | .summary { font-weight: $microformat-summary-font-weight; } 443 | 444 | abbr { 445 | cursor: $cursor-default-value; 446 | text-decoration: $microformat-abbr-font-decoration; 447 | font-weight: $microformat-abbr-font-weight; 448 | border: none; 449 | padding: $microformat-abbr-padding; 450 | } 451 | } 452 | 453 | 454 | @media #{$medium-up} { 455 | h1,h2,h3,h4,h5,h6 { line-height: $header-line-height; } 456 | h1 { font-size: $h1-font-size; } 457 | h2 { font-size: $h2-font-size; } 458 | h3 { font-size: $h3-font-size; } 459 | h4 { font-size: $h4-font-size; } 460 | h5 { font-size: $h5-font-size; } 461 | h6 { font-size: $h6-font-size; } 462 | } 463 | 464 | // Only include these styles if you want them. 465 | @if $include-print-styles { 466 | /* 467 | * Print styles. 468 | * 469 | * Inlined to avoid required HTTP connection: www.phpied.com/delay-loading-your-print-css/ 470 | * Credit to Paul Irish and HTML5 Boilerplate (html5boilerplate.com) 471 | */ 472 | .print-only { display: none !important; } 473 | @media print { 474 | * { 475 | background: transparent !important; 476 | color: $black !important; /* Black prints faster: h5bp.com/s */ 477 | box-shadow: none !important; 478 | text-shadow: none !important; 479 | } 480 | 481 | a, 482 | a:visited { text-decoration: underline;} 483 | a[href]:after { content: " (" attr(href) ")"; } 484 | 485 | abbr[title]:after { content: " (" attr(title) ")"; } 486 | 487 | // Don't show links for images, or javascript/internal links 488 | .ir a:after, 489 | a[href^="javascript:"]:after, 490 | a[href^="#"]:after { content: ""; } 491 | 492 | pre, 493 | blockquote { 494 | border: 1px solid $aluminum; 495 | page-break-inside: avoid; 496 | } 497 | 498 | thead { display: table-header-group; /* h5bp.com/t */ } 499 | 500 | tr, 501 | img { page-break-inside: avoid; } 502 | 503 | img { max-width: 100% !important; } 504 | 505 | @page { margin: 0.5cm; } 506 | 507 | p, 508 | h2, 509 | h3 { 510 | orphans: 3; 511 | widows: 3; 512 | } 513 | 514 | h2, 515 | h3 { page-break-after: avoid; } 516 | 517 | .hide-on-print { display: none !important; } 518 | .print-only { display: block !important; } 519 | .hide-for-print { display: none !important; } 520 | .show-for-print { display: inherit !important; } 521 | } 522 | } 523 | 524 | } 525 | } 526 | -------------------------------------------------------------------------------- /performance/source/iiif-image.html: -------------------------------------------------------------------------------- 1 | --- 2 | # Example of a valid page 3 | # http://iiif.io/api/image/2.0/ 4 | # Copyright © 2012-2014 Editors and contributors. 5 | # Published by the IIIF under the CC-BY license. 6 | # 7 | layout: compress 8 | --- 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Image API 2.0 - DRAFT — IIIF | International Image Interoperability Framework 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 |
35 |
36 | Home 37 | 77 |
78 |
79 | 80 |
81 |
82 |
83 |
84 |
85 |

IIIF Image API 2.0 - DRAFT

86 |
87 |
88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 |
139 |

Status of this Document

140 | 141 |

This Version: 2.0.0-draft1

142 | 143 |

Latest Stable Version: 1.1.0

144 | 145 |

Editors:

146 | 147 |
    148 |
  • Michael Appleby, Yale University
  • 149 |
  • Robert Sanderson, Stanford University
  • 150 |
  • Stuart Snydman, Stanford University
  • 151 |
  • Jon Stroop, Princeton University
  • 152 |
  • Simeon Warner, Cornell University
  • 153 |
154 | 155 |

Copyright © 2012-2014 Editors and contributors. Published by the IIIF under the CC-BY license.

156 | 157 |
158 | 159 |

Abstract

160 | 161 |

This document describes an image delivery API proposed by the International Image Interoperability Framework (IIIF) group. The IIIF Image API specifies a web service that returns an image in response to a standard HTTP or HTTPS request. The URI can specify the region, size, rotation, quality characteristics and format of the requested image. A URI can also be constructed to request basic technical information about the image to support client applications. It was conceived of to facilitate systematic reuse of image resources in digital image repositories maintained by cultural heritage organizations. This API could be adopted by any image repository or service, and can be used to retrieve static images in response to a properly constructed URI.

162 | 163 |

Please send feedback to iiif-discuss@googlegroups.com

164 | 165 |

Table of Contents

166 | 167 | 207 | 208 |

1. Audience and Scope

209 | 210 |

This document is intended for architects and developers building applications that share and consume digital images, particularly from cultural heritage institutions, museums, libraries and archives. Target applications include:

211 | 212 |
    213 |
  • Digital image repositories and distributed content networks
  • 214 |
  • Image focused web applications, such as pan/zoom viewers, book-readers, etc.
  • 215 |
  • Client applications using image content for analysis or comparison
  • 216 |
217 | 218 |

This specification concerns the use of the images by a client, but not management of the images by the server. It covers how to respond to the requests given in a particular URI syntax, but does not cover methods of implementation such as rotation algorithms, transcoding, color management, compression, or how to respond to URIs that do not conform to the specified syntax. This allows flexibility for implementation in domains with particular constraints or specific community practices, while supporting interoperability in the general case.

219 | 220 |

2. URI Syntax

221 | 222 |

The IIIF Image API can be called in two ways:

223 | 224 |
    225 |
  • Request an image, which may be part of a larger image
  • 226 |
  • Request a description of the image characteristics and functionality available for that image
  • 227 |
228 | 229 |

Both convey the request’s information in the path segments of the URI, rather than as query parameters. This makes responses easier to cache, either at the server or by standard web-caching infrastructure. It also permits a minimal implementation using pre-computed files in a matching directory structure.

230 | 231 |

There are four parameters shared by the requests, and other IIIF specifications:

232 | 233 |
234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 |
NameDescription
schemeIndicates the use of the HTTP or HTTPS protocol in calling the service.
serverThe host server on which the service resides.
prefixThe path on the host server to the service. This prefix is optional, but may be useful when the host server supports multiple services. The prefix may contain multiple path segments, delimited by slashes, but all other special characters must be encoded. See URI Encoding and Decoding for more information.
identifierThe identifier of the requested image, expressed as a string. This may be an ark, URN, filename, or other identifier. Special characters must be URI encoded.
259 | 260 |

The combination of these parameters forms the image’s Base URI and identifies the underlying image content. It is constructed according to the following URI Template (RFC6570):

261 | 262 |
{scheme}://{server}{/prefix}/{identifier}
 263 | 
264 | 265 |

When the base URI is dereferenced, the interaction should result in the Image Information document. It is recommended that the response be a 303 status redirection to the Image Information document’s URI. Implementations may also exhibit other behavior for the base URI beyond the scope of this specification in response to HTTP request headers and methods.

266 | 267 |

To allow for extensions, this specification does not define the server behavior when it receives requests that do not match either the Base URI or one of the described URI syntaxes below.

268 | 269 |

2.1. Image Request URI Syntax

270 | 271 |

The IIIF Image API URI for requesting an image must conform to the following URI Template:

272 | 273 |
{scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
 274 | 
275 | 276 |

For example:

277 | 278 |
http://www.example.org/image-service/abcd1234/full/full/0/default.jpg
 279 | 
280 | 281 |

The sections of the Image Request URI include region, size, rotation, quality and format parameters, which define the characteristics of the returned image. These are described in detail in Image Request Parameters.

282 | 283 |

2.2. Image Information Request URI Syntax

284 | 285 |

The URI for requesting image information must conform to the following URI Template:

286 | 287 |
{scheme}://{server}{/prefix}/{identifier}/info.json
 288 | 
289 | 290 |

For example:

291 | 292 |
http://www.example.org/image-service/abcd1234/info.json
 293 | 
294 | 295 |

For each image made available, the server, prefix and identifier components of the information request must be identical to those for the image request described above. The Image Information document is described in detail in the Image Information section.

296 | 297 |

3. Identifier

298 | 299 |

The API places no restrictions on the form of the identifiers that a server may use or support, although the identifier must be expressed as a string. All special characters (e.g. ? or #) must be URI encoded to avoid unpredictable client behaviors. The URI syntax relies upon slash (/) separators so any slashes in the identifier must be URI encoded (aka. percent-encoded, replace / with %2F ). See the additional discussion in URI Encoding and Decoding.

300 | 301 |

4. Image Request Parameters

302 | 303 |

All parameters described below are required for compliant construction of a IIIF Image API URI. The sequence of parameters in the URI must be in the order described below. The order of the parameters is also intended as the order of the operations by which the service should manipulate the image content. Thus, the requested image content is first extracted as a region of the complete image, then scaled to the requested size, rotated and transformed into the color depth and format. This resulting image content is returned as the representation for the URI. Image and region dimensions in pixels are always given as an integer numbers. Intermediate calculations may use floating point numbers and the rounding method is implementation specific. Some parameters, notably percentages, may be specified with floating point numbers. These should have at most 10 decimal digits and consist only of decimal digits and “.” with a leading zero if less than 1.

304 | 305 |

4.1. Region

306 | 307 |

The region parameter defines the rectangular portion of the full image to be returned. Region can be specified by pixel coordinates, percentage or by the value “full”, which specifies that the entire image should be returned.

308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 |
FormDescription
fullThe complete image is returned, without any cropping.
x,y,w,hThe region of the full image to be returned is defined in terms of absolute pixel values. The value of x represents the number of pixels from the 0 position on the horizontal axis. The value of y represents the number of pixels from the 0 position on the vertical axis. Thus the x,y position 0,0 is the upper left-most pixel of the image. w represents the width of the region and h represents the height of the region in pixels.
pct:x,y,w,hThe region to be returned is specified as a sequence of percentages of the full image’s dimensions, as reported in the Image Information document. Thus, x represents the number of pixels from the 0 position on the horizontal axis, calculated as a percentage of the reported width. w represents the width of the region, also calculated as a percentage of the reported width. The same applies to y and h respectively. These may be floating point numbers.
331 | 332 |

If the request specifies a region which extends beyond the reported dimensions of the full image, then the service should return an image cropped at the image’s edge, rather than adding empty space.

333 | 334 |

If the requested region’s height or width is zero, or if the region is entirely outside the bounds of the full image’s reported dimensions, then the server should return a 400 status code.

335 | 336 |

Examples:

337 | 338 | 339 | 340 | 341 | 346 | 351 | 352 | 353 | 358 | 364 | 365 | 366 | 372 | 373 | 374 | 375 |
342 | Full Size 343 |

1 size=full

344 |

.../full/full/0/default.jpg

345 |
347 | Region by Pixels 348 |

2 region=125,15,120,140

349 |

.../125,15,120,140/full/0/default.jpg

350 |
354 | Region by Percent 355 |

3 region=pct:41.6,7.5,40,70

356 |

.../pct:41.6,7.5,40,70/full/0/default.jpg

357 |
359 | Region by Pixels 360 |

4 region=125,15,200,200

361 |

.../125,15,200,200/full/0/default.jpg

362 |

N.B. Returned image is 175,185 px

363 |
367 | Region by Percent 368 |

5 region=pct:41.6,7.5,66.6,100

369 |

.../pct:41.6,7.5,66.6,100/full/0/default.jpg

370 |

N.B. Returned image is 175,185 px

371 |
376 | 377 |

4.2. Size

378 | 379 |

The size parameter determines the dimensions to which the extracted region is to be scaled.

380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 |
FormDescription
fullThe extracted region is not scaled, and is returned at its full size.
w,The extracted region should be scaled so that its width is exactly equal to w, and the height will be a calculated value that maintains the aspect ratio of the requested region.
,hThe extracted region should be scaled so that its height is exactly equal to h, and the width will be a calculated value that maintains the aspect ratio of the requested region.
pct:nThe width and height of the returned image is scaled to n% of the width and height of the extracted region. The aspect ratio of the returned image is the same as that of the extracted region.
w,hThe width and height of the returned image are exactly w and h. The aspect ratio of the returned image may be different than the extracted region, resulting in a distorted image.
!w,hThe image content is scaled for the best fit such that the resulting width and height are less than or equal to the requested width and height. The exact scaling may be determined by the service provider, based on characteristics including image quality and system performance. The dimensions of the returned image content are calculated to maintain the aspect ratio of the extracted region.
415 | 416 |

If the resulting height or width is zero, then the server should return a 400 (bad request) status code.

417 | 418 |

The image server may support scaling beyond the full size of the extracted region.

419 | 420 |

Examples:

421 | 422 | 423 | 424 | 425 | 430 | 435 | 440 | 441 | 442 | 447 | 452 | 458 | 459 | 460 |
426 | Full Size 427 |

1 size=full

428 |

.../full/full/0/default.jpg

429 |
431 | Size by Width 432 |

2 size=150,

433 |

.../full/150,/0/default.jpg

434 |
436 | Size by Height 437 |

3 size=,150

438 |

.../full/,150/0/default.jpg

439 |
443 | Size by Percent 444 |

4 size=pct:50

445 |

.../full/pct:50/0/default.jpg

446 |
448 | Size by Width,Height 449 |

5 size=225,100

450 |

.../full/225,100/0/default.jpg

451 |
453 | Size By Bang Width Height 454 |

6 size=!225,100

455 |

.../full/!225,100/0/default.jpg

456 |

N.B. Returned image is 150,100 px

457 |
461 | 462 |

4.3. Rotation

463 | 464 |

The rotation value represents the number of degrees of clockwise rotation from the original, and may be any floating point number from 0 to 360.

465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 |
FormDescription
nThe degrees of clockwise rotation from the original, from 0 up to 360.
480 | 481 |

A rotation value that is out of range or unsupported should result in a 400 status code.

482 | 483 |

In most cases a rotation will change the width and height dimensions of the returned image. The service should return an image that contains all of the image contents requested in the region and size parameters, even if the dimensions of the returned image file are different than specified in the size parameter. The image contents should not be scaled as a result of the rotation, and there should be no additional space between the corners of the rotated image contents and the bounding box of the returned image content.

484 | 485 |

For non-90-degree rotations the API does not specify the background color.

486 | 487 |

Examples:

488 | 489 | 490 | 491 | 492 | 497 | 502 | 503 | 504 | 509 | 514 | 515 | 516 |
493 | Rotation 0 494 |

1 rotation=0

495 |

.../full/full/0/default.jpg

496 |
498 | Rotation 180 499 |

2 rotation=180

500 |

.../full/full/180/default.jpg

501 |
505 | Rotation 90 506 |

3 rotation=90

507 |

.../full/full/90/default.jpg

508 |
510 | Rotation 22.5 511 |

4 rotation=22.5

512 |

.../full/full/22.5/default.jpg

513 |
517 | 518 |

4.4. Quality

519 | 520 |

The quality parameter determines whether the image is delivered in color, grayscale or black and white.

521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 |
QualityParameter Returned
defaultThe image is returned using the server’s default quality (e.g. color, gray or bitonal as below) for the image.
colorThe image is returned in full color.
grayThe image is returned in grayscale, where each pixel is black, white or any shade of gray in between.
bitonalThe image returned is bitonal, where each pixel is either black or white.
548 | 549 |

A quality value that is unsupported should result in a 400 status code.

550 | 551 |

Examples:

552 | 553 | 554 | 555 | 556 | 561 | 566 | 567 | 568 | 573 | 578 | 579 | 580 |
557 | Default Quality 558 |

1 quality=default

559 |

.../full/full/0/default.jpg

560 |
562 | Color Quality 563 |

2 quality=color

564 |

.../full/full/0/color.jpg

565 |
569 | Gray Quality 570 |

3 quality=gray

571 |

.../full/full/0/gray.jpg

572 |
574 | Bitonal Quality 575 |

4 quality=bitonal

576 |

.../full/full/0/bitonal.jpg

577 |
581 | 582 |

4.5. Format

583 | 584 |

The format of the returned image is expressed as an extension at the end of the URI.

585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 |
ExtensionMIME Type
jpgimage/jpeg
tifimage/tiff
pngimage/png
gifimage/gif
jp2image/jp2
pdfapplication/pdf
620 | 621 |

A format value that is unsupported should result in a 400 status code.

622 | 623 |

Examples:

624 | 625 |
    626 |
  1. .../full/full/0/default.jpg
  2. 627 |
  3. .../full/full/0/default.png
  4. 628 |
  5. .../full/full/0/default.tif
  6. 629 |
630 | 631 |

4.6. Order of Implementation

632 | 633 |

The sequence of parameters in the URI is intended to express the order in which image manipulations are made against the full image content. This is important to consider when implementing the service because applying the same parameters in a different sequence will often result in a different image being delivered. The order is critical so that the application calling the service reliably receives the output it expects.

634 | 635 |

The parameters should be interpreted as if the the sequence of image manipulations were:

636 | 637 |

Region THEN Size THEN Rotation THEN Quality THEN Format

638 | 639 | 640 | 641 | 642 | 647 | 648 | 649 |
643 | Order of Implementation 644 |

1 region=125,15,120,140 size=90, rotation=345 quality=gray

645 |

.../125,15,120,140/90,/345/gray.jpg

646 |
650 | 651 |

4.7. Canonical URI Syntax

652 | 653 |

There are several reasons why a canonical URI syntax is desirable:

654 | 655 |
    656 |
  • It enables static, file-system based implementations, which will have only a single URI at which the content is available.
  • 657 |
  • Caching becomes significantly more efficient, both client and server side, when the URIs used are the same between systems and sessions.
  • 658 |
  • Response times can be improved by avoiding redirects from a requested non-canonical URI syntax to the canonical syntax by using the canonical form directly
  • 659 |
660 | 661 |

In order to support the above requirements, clients should construct the image request URIs using to following canonical parameter values where possible.

662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 |
ParameterCanonical value
region“full” if the whole image is requested, otherwise the x,y,w,h description of the region.
size“full” if the default size is requested, otherwise the pixel dimensions w,h.
rotationAn integer if possible, and trimming any trailing zeros in a decimal value, and a leading 0 if the value is below 1.
quality“default” unless a quality that is different from the default quality is requested.
formatExplicit format string required; ‘jpg’ is preferred.
693 | 694 |

When the client requests an image, the server may add a link header to the response that indicates the canonical URI for that request:

695 | 696 |
Link: <http://iiif.example.com/server/full/full/0/default.jpg>;rel="canonical"
 697 | 
698 | 699 |

5. Information Request

700 | 701 |

The Image Information document contains both metadata about the image, such as full height and width, and functionality available for it, such as the formats in which it may be retrieved. The service must return this information about the image. The request for technical information must conform to the URI Template:

702 | 703 |
{scheme}://{server}{/prefix}/{identifier}/info.json
 704 | 
705 | 706 |

The syntax for the response is JSON-LD. The content-type of the response must be either “application/json” (regular JSON), or “application/ld+json” (JSON-LD). If the client explicitly wants the JSON-LD content-type, then it must specify this in an Accept header, otherwise the server must return the regular JSON content-type.

707 | 708 |

If the regular JSON content-type is returned, then it is recommended that the server provide a link header to the context document. The syntax for the link header is below, and further described in section 6.8 of the JSON-LD specification. If the client requests “application/ld+json”, the link header may still be included but must be ignored. The entity body is identical regardless of the content-type, including the @context field.

709 | 710 |
Link: <http://iiif.io/api/image/2/context.json>
 711 |             ; rel="http://www.w3.org/ns/json-ld#context"
 712 |             ; type="application/ld+json"
 713 | 
714 | 715 |

Servers should send the Access-Control-Allow-Origin header with the value * in response to information requests. The syntax is shown below and is described in the CORS specification. This header is required in order to allow the JSON responses to be used by Web applications hosted on different servers.

716 | 717 |
Access-Control-Allow-Origin: *
 718 | 
719 | 720 |

5.1. Image Information

721 | 722 |

The JSON in the response will include the following properties:

723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 |
PropertyRequired?Description
@contextRequiredThe context document that describes the semantics of the terms used in the document. This must be the URI: http://iiif.io/api/image/2.0/context.json for version 2.0 of the IIIF Image API. This document allows the response to be interpreted as RDF, using the JSON-LD serialization.
@idRequiredThe Base URI of the image (as defined in URI Syntax, including scheme, server, prefix and identifier without a trailing slash.
widthRequiredThe width of the full image.
heightRequiredThe height of the full image.
protocolRequiredThe URI http://iiif.io/api/image which can be used to determine that the document describes an image service which is a version of the IIIF Image API.
profileRequiredAn array of profiles, indicated by either a URI or an object describing the features supported. The first entry in the array must be a compliance level URI, as defined below.
scale_factorsOptionalSome image servers support the creation of multiple resolution levels for a single image in order to optimize the efficiency in delivering images of different sizes. The scale_factors property expresses a set of resolution scaling factors. For example, a scale factor of 4 indicates that the service can efficiently deliver images at 1/4 or 25% of the height and width of the full image.
sizesOptionalA set of dimensions that the server has available, expressed in the “w,h” syntax. This may be used to let a client know the sizes that are available when the server does not support requests for arbitrary sizes, or simply as a hint that requesting an image of this size may result in a faster response.
tile_widthOptionalSome image servers efficiently support delivery of predefined tiles enabling easy assembly of portions of the image. It is assumed that the same tile sizes are used for all scale factors supported. The tile_width property expresses the width of the predefined tiles.
tile_heightOptionalThe tile_height property expresses the height of the predefined tiles. See description of tile_width for more information.
785 | 786 |

Image profiles have the following properties:

787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 |
PropertyRequired?Description
formatsOptionalThe set of image format parameter values available for the image.
qualitiesOptionalThe set of image quality parameter values available for the image.
supportsOptionalThe set of additional features supported beyond those declared in the compliance level document
814 | 815 |

The set of features that may be specified in the supports property of an Image profile are:

816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 |
Feature NameDescription
base_uri_redirectThe base URI of the service will redirect to the Image Information document
canonical_link_headerThe canonical image URI HTTP link header is provided on image responses
corsThe CORS HTTP header is provided on all responses
jsonld_media_typeThe JSON-LD media type is provided when JSON-LD is requested
profile_link_headerThe profile link header is provided on image responses
region_by_pctRegions of images may be requested by percentage
region_by_pxRegions of images may be requested by pixel dimensions
rotation_arbitraryRotation of images may be requested by degrees other than multiples of 90
rotation_by_90sRotation of images may be requested by degrees in multiples of 90
size_above_fullSize of images may be requested larger than the “full” size
size_by_forced_whSize of images may be requested in the form “!w,h”
size_by_hSize of images may be requested in the form “,h”
size_by_pctSize of images may be requested in the form “pct:n”
size_by_wSize of images may be requested in the form “w,”
size_by_whSize of images may be requested in the form “w,h”
887 | 888 |

The set of features, formats and qualities supported is the union of those declared in all of the external profile documents and any embedded profile objects. If a property is not present in either the profile document or the supports property of an embedded profile, then a client must assume that the feature is not supported.

889 | 890 |

The JSON response must conform to the structure shown in the following example:

891 | 892 |
893 |
{
 894 |   "@context" : "http://iiif.io/api/image/2/context.json",
 895 |   "@id" : "http://www.example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C",
 896 |   "protocol" : "http://iiif.io/api/image",
 897 |   "width" : 6000,
 898 |   "height" : 4000,
 899 |   "scale_factors" : [ 1, 2, 4 ],
 900 |   "sizes" : [ "150,100", "360,240", "3600,2400" ],
 901 |   "tile_width" : 1024,
 902 |   "tile_height" : 1024,
 903 |   "profile" : [
 904 |     "http://iiif.io/api/image/2/level2.json",
 905 |     {
 906 |       "formats" : [ "jpg", "png" ],
 907 |       "qualities" : [ "default" ],
 908 |       "supports" : [
 909 |           "canonical_link_header", "rotation_arbitrary"
 910 |       ]
 911 |     }
 912 |   ]
 913 | }
914 |
915 | 916 |

5.2 Extensions

917 | 918 |

Local additions to the image information document may be specified in two ways:

919 | 920 |
    921 |
  1. Extra properties may be added to the document to provide information not defined in this specification. Clients must ignore properties that are not understood.
  2. 922 |
  3. URIs may be added to the supports list of a profile to cover features not defined in this specification, and similarly clients must ignore URIs that are not understood.
  4. 923 |
924 | 925 |
926 |
{
 927 |   "@context" : "http://iiif.io/api/image/2/context.json",
 928 |   // ...
 929 |   "documentation" : "http://www.example.com/my/documentation.html",
 930 |   // ...
 931 |   "profile" : [
 932 |     "http://iiif.io/api/image/2/level2.json",
 933 |     "http://www.example.com/my/profile-level-42.json",
 934 |     {"supports" : ["http://www.example.com/my/feature.html"]}
 935 |   ]
 936 | }
937 |
938 | 939 |

6. Compliance Levels

940 | 941 |

The Image Information document must specify the extent to which the API is supported by including a compliance level URI as the first entry in the profile property. This URI links to a description of the highest compliance level for which all requirements are met. The URI must be one of those given in Image API Compliance. This description contains the profile related features, as discussed in Image Information. A server may declare different compliance levels for different images.

942 | 943 |

The compliance level URI may also be given in the HTTP Link header (RFC5988) with the parameter rel="profile", and thus a complete header might look like:

944 | 945 |
Link: <http://iiif.io/api/image/2/level1.json>;rel="profile"
 946 | 
947 | 948 |

7. Server Responses

949 | 950 |

7.1. Successful Responses

951 | 952 |

Servers may transmit HTTP responses with 200 (Successful) or 3xx (Redirect) status codes when the request has been successfully processed. If the status code is 200, then the entity-body must be the requested image or information response. If the status code is 301, 302, 303, or 304, then the entity-body is unrestricted, but it is recommended to be empty. If the status code is 301, 302, or 303 then the Location HTTP Header must be set containing the URI of the image that fulfills the request. This enables servers to have a single canonical URI to promote caching of responses. Status code 304 is handled exactly as per the HTTP specification. Clients should expect to encounter all of these situations and must not assume that the entity-body of the initial response necessarily contains the image data.

953 | 954 |

7.2. Error Conditions

955 | 956 |

The order in which servers parse requests and detect errors is not specified. A request is likely to fail on the first error encountered and return an appropriate HTTP status code, with common codes given in the list below. It is recommended that the body of the error response includes a human-readable description of the error in either plain text or html.

957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | 995 |
Status CodeDescription
400 Bad RequestThis response is used when it is impossible for the server to fulfil the request, as the syntax of the request is incorrect. For example, this would be used if the size parameter does not match any of the specified syntaxes.
401 UnauthorizedAuthentication is required and not provided. See Section 7 below for details.
403 ForbiddenThe user, authenticated or not, is not permitted to perform the requested operation.
404 Not FoundThe image resource specified by identifier does not exist, or the value of one or more of the parameters is not supported for this image.
500 Internal Server ErrorThe server encountered an unexpected error that prevented it from fulfilling the request.
501 Not ImplementedA valid IIIF request that is not implemented by this server.
503 Service UnavailableUsed when the server is busy/temporarily unavailable due to load/maintenance issues. An alternative to connection refusal with the option to specify a back-off period.
996 | 997 |

8. Authentication

998 | 999 |

This API does not specify whether the image server will support authentication or what mechanism it might use. In the case of “401 Unauthorized” HTTP response, the content of the WWW-Authenticate header will depend on the authentication mechanism supported by the server. If the server supports HTTP Basic or Digest authentication then the header should follow RFC2617, for example:

1000 | 1001 |
WWW-Authenticate: Basic realm="Images"
1002 | 
1003 | 1004 |

9. URI Encoding and Decoding

1005 | 1006 |

The URI syntax of this API relies upon slash (/) separators which must not be encoded. Clients must percent-encode special characters (the to-encode set below: percent and gen-delims of RFC3986 except the colon) within the components of requests. For example, any slashes within the identifier part of the URI must be percent-encoded. Encoding is necessary only for the identifier because other components will not include special characters.

1007 | 1008 |
to-encode = "/" / "?" / "#" / "[" / "]" / "@" / "%"
1009 | 
1010 | 1011 |

Upon receiving an API request, a server must first split the URI path on slashes and then decode any percent-encoded characters in each component.

1012 | 1013 |

Additionally, if identifiers include any characters outside the US-ASCII set then the encoding to octets must be defined consistently on client and server, and the octets must be percent-encoded. Percent-encoding other characters introduces no ambiguity but is unnecessary.

1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 |
ParametersURI path
identifier=id1 region=full size=full rotation=0 quality=defaultid1/full/full/0/default
identifier=id1 region=0,10,100,200 size=pct:50 rotation=90 quality=default format=pngid1/0,10,100,200/pct:50/90/default.png
identifier=id1 region=pct:10,10,80,80 size=50, rotation=22.5 quality=color format=jpgid1/pct:10,10,80,80/50,/22.5/color.jpg
identifier=bb157hs6068 region=full size=full rotation=270 quality=gray format=jpgbb157hs6068/full/full/270/gray.jpg
identifier=ark:/12025/654xz321 region=full size=full rotation=0 quality=defaultark:%2F12025%2F654xz321/full/full/0/default
identifier=urn:foo:a123,456 region=full size=full rotation=0 quality=defaulturn:foo:a123,456/full/full/0/default
identifier=urn:sici:1046-8188(199501)13:1%3C69:FTTHBI%3E2.0.TX;2-4 region=full size=full rotation=0 quality=defaulturn:sici:1046-8188(199501)13:1%253C69:FTTHBI%253E2.0.TX;2-4/full/full/0/default
identifier=http://example.com/?54#a region=full size=full rotation=0 quality=defaulthttp:%2F%2Fexample.com%2F%3F54%23a/full/full/0/default
1057 | 1058 |

Servers which are incapable of processing arbitrarily encoded identifiers should make their best efforts to expose only image identifiers for which clients will not encode any of the characters, and thus it is recommended to limit characters in identifiers to letters, numbers and the underscore character.

1059 | 1060 |

10. Security Considerations

1061 | 1062 |

This API defines a URI syntax and the semantics associated with its components. The composition of URIs has few security considerations except possible exposure of sensitive information in URIs or revealing of browse/view behavior of users.

1063 | 1064 |

Server applications implementing this API should consider possible denial-of-service attacks, and authentication vulnerabilities based on DNS spoofing. Applications must be careful to parse incoming requests (URIs) in ways that avoid overflow or injection attacks.

1065 | 1066 |

Early sanity checking of URIs (lengths, trailing GET, invalid characters, out-of-range parameters) and rejection with appropriate response codes is recommended.

1067 | 1068 |

11. Appendices

1069 | 1070 |

A. Implementation Notes

1071 | 1072 |
    1073 |
  • For use cases that enable the saving of the image, it is recommended to use the HTTP Content-Disposition header (RFC6266) to provide a convenient filename that distinguishes the image, based on the identifier and parameters provided.
  • 1074 |
  • This specification makes no assertion about the rights status of requested images or any other descriptive metadata, whether or not authentication has been accomplished. Please see the IIIF Presentation API for rights and other information.
  • 1075 |
  • This API does not specify how image servers fulfill requests, what quality the returned images will have for different parameters, or how parameters may affect performance.
  • 1076 |
  • Image identifiers that include the slash (/ %2F) or backslash (\ %5C) characters may cause problems with some HTTP servers. Apache servers from version 2.2.18 support the AllowEncodedSlashes NoDecode configuration directive which will correctly pass these characters to client applications without rejecting or decoding them. Servers using older versions of Apache and local identifiers which include these characters will need to use a workaround such as internally translating or escaping slash and backslash to safe value (perhaps by double URI-encoding them).
  • 1077 |
  • As described in Rotation, in order to retain the size of the requested image contents, rotation will change the width and height dimensions of the returned image file. A formula for calculating the dimensions of the returned image file for a given rotation can be found here.
  • 1078 |
1079 | 1080 |

B. Versioning

1081 | 1082 |

Starting with version 2.0, this specification follows Semantic Versioning. See the note Versioning of APIs for details regarding how this is implemented.

1083 | 1084 |

C. Acknowledgments

1085 | 1086 |

The production of this document was generously supported by a grant from the Andrew W. Mellon Foundation.

1087 | 1088 |

Many thanks to Ben Albritton, Matthieu Bonicel, Anatol Broder, Kevin Clarke, Tom Cramer, Ian Davis, Neil Jefferies, Scotty Logan, Sean Martin, Roger Mathisen, Lynn McRae, Willy Mene, Mark Patton, Petter Rønningsen, and Brian Tingle for your thoughtful contributions to the effort and written feedback. Thanks also to the members of the IIIF Community for their continuous engagement, innovative ideas and feedback.

1089 | 1090 |

D. Change Log

1091 | 1092 | 1093 | 1094 | 1095 | 1096 | 1097 | 1098 | 1099 | 1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 1106 | 1107 | 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 1128 | 1129 | 1130 | 1131 | 1132 | 1133 | 1134 | 1135 | 1136 | 1137 | 1138 | 1139 | 1140 | 1141 |
DateDescription
2014-05-XXVersion 2.0 (Voodoo Bunny) RFC View change log
2013-09-17Version 1.1 released.
2013-09-04Added @context to Image Information Request table in section 5.
2013-06-26Changed quality parameter definitions in section 4.4.
2013-06-17Draft release 1.1. View change log.
2012-08-10Release 1.0
2012-07-13Incorporates responses to RFC feedback
2012-03-09Initial release
2012-04-130.2 after internal review and IIIF April Meeting
2012-05-02RFC version
1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1153 | 1154 | 1155 | 1164 | 1165 | 1166 | 1167 | 1168 | --------------------------------------------------------------------------------