├── .editorconfig ├── .gitignore ├── README.md ├── deploy.sh ├── package.json └── src ├── data.json ├── styles ├── components │ ├── _fast-ft.scss │ └── _story.scss ├── layouts │ ├── _grid-headlines.scss │ └── _grid.scss └── main.scss └── templates ├── index.pug └── partials ├── fast-ft.pug ├── story.pug └── support.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | indent_size = 2 9 | indent_style = space 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | public/ 3 | 4 | .DS_Store 5 | Thumbs.db 6 | npm-debug.log 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSS grid layout demo 2 | 3 | > The aim of CSS was to separate content and style but our layouts are as tied to our markup as ever. Grid layout has the chance to deliver a huge shift in the way we rationalise layout systems for the web and drastically reduce the complexity of the markup and styles currently required. 4 | 5 | - [Original article](http://maketea.co.uk/2016/09/28/css-grid-layout-is-a-step-change.html) 6 | - [View demo](https://i-like-robots.github.io/grid-layout-demo/) 7 | 8 | ## System dependencies 9 | 10 | - Node 4+ 11 | 12 | ## Local setup 13 | 14 | ```sh 15 | # clone this repo 16 | git clone git@github.com:i-like-robots/grid-layout-demo.git && cd grid-layout-demo 17 | 18 | # install dependencies 19 | npm install 20 | 21 | # build the demo 22 | npm run build 23 | 24 | # open the demo 25 | open public/index.html 26 | ``` 27 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -o errexit #abort if any command fails 3 | 4 | deploy_directory=${GIT_DEPLOY_DIR:-public} 5 | deploy_branch=${GIT_DEPLOY_BRANCH:-gh-pages} 6 | 7 | #if no user identity is already set in the current git environment, use this: 8 | default_username=${GIT_DEPLOY_USERNAME:-deploy.sh} 9 | default_email=${GIT_DEPLOY_EMAIL:-} 10 | 11 | #repository to deploy to. must be readable and writable. 12 | repo=${GIT_DEPLOY_REPO:-origin} 13 | 14 | # Parse arg flags 15 | while : ; do 16 | if [[ $1 = "-v" || $1 = "--verbose" ]]; then 17 | verbose=true 18 | shift 19 | elif [[ $1 = "-s" || $1 = "--setup" ]]; then 20 | setup=true 21 | shift 22 | elif [[ $1 = "-e" || $1 = "--allow-empty" ]]; then 23 | allow_empty=true 24 | shift 25 | else 26 | break 27 | fi 28 | done 29 | 30 | #echo expanded commands as they are executed (for debugging) 31 | function enable_expanded_output { 32 | if [ $verbose ]; then 33 | set -o xtrace 34 | set +o verbose 35 | fi 36 | } 37 | 38 | #this is used to avoid outputting the repo URL, which may contain a secret token 39 | function disable_expanded_output { 40 | if [ $verbose ]; then 41 | set +o xtrace 42 | set -o verbose 43 | fi 44 | } 45 | 46 | enable_expanded_output 47 | 48 | function set_user_id { 49 | if [[ -z `git config user.name` ]]; then 50 | git config user.name "$default_username" 51 | fi 52 | if [[ -z `git config user.email` ]]; then 53 | git config user.email "$default_email" 54 | fi 55 | } 56 | 57 | function restore_head { 58 | if [[ $previous_branch = "HEAD" ]]; then 59 | #we weren't on any branch before, so just set HEAD back to the commit it was on 60 | git update-ref --no-deref HEAD $commit_hash $deploy_branch 61 | else 62 | git symbolic-ref HEAD refs/heads/$previous_branch 63 | fi 64 | 65 | git reset --mixed 66 | } 67 | 68 | if ! git diff --exit-code --quiet --cached; then 69 | echo Aborting due to uncommitted changes in the index >&2 70 | exit 1 71 | fi 72 | 73 | commit_title=`git log -n 1 --format="%s" HEAD` 74 | commit_hash=`git log -n 1 --format="%H" HEAD` 75 | previous_branch=`git rev-parse --abbrev-ref HEAD` 76 | 77 | if [ $setup ]; then 78 | mkdir -p "$deploy_directory" 79 | git --work-tree "$deploy_directory" checkout --orphan $deploy_branch 80 | git --work-tree "$deploy_directory" rm -r "*" 81 | git --work-tree "$deploy_directory" add --all 82 | git --work-tree "$deploy_directory" commit -m "initial publish"$'\n\n'"generated from commit $commit_hash" 83 | git push $repo $deploy_branch 84 | restore_head 85 | exit 86 | fi 87 | 88 | if [ ! -d "$deploy_directory" ]; then 89 | echo "Deploy directory '$deploy_directory' does not exist. Aborting." >&2 90 | exit 1 91 | fi 92 | 93 | if [[ -z `ls -A "$deploy_directory" 2> /dev/null` && -z $allow_empty ]]; then 94 | echo "Deploy directory '$deploy_directory' is empty. Aborting. If you're sure you want to deploy an empty tree, use the -e flag." >&2 95 | exit 1 96 | fi 97 | 98 | disable_expanded_output 99 | git fetch --force $repo $deploy_branch:$deploy_branch 100 | enable_expanded_output 101 | 102 | #make deploy_branch the current branch 103 | git symbolic-ref HEAD refs/heads/$deploy_branch 104 | 105 | #put the previously committed contents of deploy_branch branch into the index 106 | git --work-tree "$deploy_directory" reset --mixed --quiet 107 | 108 | git --work-tree "$deploy_directory" add --all 109 | 110 | set +o errexit 111 | diff=$(git --work-tree "$deploy_directory" diff --exit-code --quiet HEAD)$? 112 | set -o errexit 113 | case $diff in 114 | 0) echo No changes to files in $deploy_directory. Skipping commit.;; 115 | 1) 116 | set_user_id 117 | git --work-tree "$deploy_directory" commit -m \ 118 | "publish: $commit_title"$'\n\n'"generated from commit $commit_hash" 119 | 120 | disable_expanded_output 121 | #--quiet is important here to avoid outputting the repo URL, which may contain a secret token 122 | git push --quiet $repo $deploy_branch 123 | enable_expanded_output 124 | ;; 125 | *) 126 | echo git diff exited with code $diff. Aborting. Staying on branch $deploy_branch so you can debug. To switch back to master, use: git symbolic-ref HEAD refs/heads/master && git reset --mixed >&2 127 | exit $diff 128 | ;; 129 | esac 130 | 131 | restore_head 132 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grid-layout-demo", 3 | "private": true, 4 | "version": "0.0.0", 5 | "description": "", 6 | "main": "", 7 | "scripts": { 8 | "build-html": "pug --pretty src/templates/index.pug -O src/data.json -o public", 9 | "build-styles": "node-sass src/styles/main.scss public/main.css --recursive", 10 | "watch-html": "npm run build-html -- --watch", 11 | "watch-styles": "npm run build-styles -- --watch", 12 | "build": "parallelshell 'npm run build-styles' 'npm run build-html'", 13 | "watch": "parallelshell 'npm run watch-styles' 'npm run watch-html'" 14 | }, 15 | "author": "Matt Hinchliffe", 16 | "license": "MIT", 17 | "devDependencies": { 18 | "node-sass": "^3.10.0", 19 | "parallelshell": "^2.0.0", 20 | "pug": "^2.0.0-beta6", 21 | "pug-cli": "^1.0.0-alpha6" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "headlines": [ 3 | { 4 | "guid": "dabf5f54-a4d9-4c78-bf16-94abfb5ce7ec", 5 | "mainImage": "https://unsplash.it/640/360?random", 6 | "title": "Ex pariatur do esse anim occaecat ipsum", 7 | "summary": "Commodo minim adipisicing do cillum ullamco ex commodo est voluptate ea veniam.", 8 | "date": "Sat Oct 22 2016 06:07:57 GMT+0000 (UTC)", 9 | "tags": [ 10 | "Opinion", 11 | "Indexia", 12 | "Madagascar", 13 | "Ward Gray" 14 | ], 15 | "related": [ 16 | { 17 | "guid": "399fdfe3-f2a6-4860-88f7-bdcefc23be31", 18 | "title": "Duis officia qui excepteur tempor nulla", 19 | "date": "Sat Oct 22 2016 03:35:49 GMT+0000 (UTC)" 20 | }, 21 | { 22 | "guid": "9412a65a-a9c1-4bc1-9e99-a9f54e422363", 23 | "title": "Cillum incididunt est laboris aliqua", 24 | "date": "Sat Oct 22 2016 04:42:07 GMT+0000 (UTC)" 25 | }, 26 | { 27 | "guid": "f321f767-da86-4194-8311-4f8f35debff8", 28 | "title": "Ea culpa sit dolore enim Lorem ipsum", 29 | "date": "Sat Oct 22 2016 03:55:46 GMT+0000 (UTC)" 30 | } 31 | ] 32 | }, 33 | { 34 | "guid": "b3c3a5e1-a9bc-4653-a307-bdd058197fcd", 35 | "mainImage": "https://unsplash.it/640/360?random", 36 | "title": "Ullamco amet veniam exercitation magna", 37 | "summary": "Aliquip ea aute quis velit consectetur. Pariatur minim non ipsum esse ullamco.", 38 | "date": "Sat Oct 22 2016 18:07:41 GMT+0000 (UTC)", 39 | "tags": [ 40 | "Companies", 41 | "Quonk", 42 | "Lebanon", 43 | "Kaufman Stuart" 44 | ], 45 | "variation": "picture" 46 | }, 47 | { 48 | "guid": "3df8683f-a5c0-40c2-9cd5-e2e64a33377f", 49 | "mainImage": "https://unsplash.it/640/360?random", 50 | "title": "Laboris dolor velit officia occaecat", 51 | "summary": "Et occaecat velit aute excepteur adipisicing cupidatat duis aute aliqua officia.", 52 | "date": "Sun Oct 23 2016 16:07:12 GMT+0000 (UTC)", 53 | "tags": [ 54 | "World", 55 | "Intradisk", 56 | "Afghanistan", 57 | "Fitzpatrick Wolfe" 58 | ] 59 | }, 60 | { 61 | "guid": "9fdf807d-c449-4da3-a1d6-1c985d7ba8a0", 62 | "mainImage": "https://unsplash.it/640/360?random", 63 | "title": "Cupidatat magna adipisicing exercitation in", 64 | "summary": "Occaecat deserunt esse reprehenderit proident ut amet mollit consequat voluptate eu.", 65 | "date": "Sun Oct 23 2016 16:28:45 GMT+0000 (UTC)", 66 | "tags": [ 67 | "Markets", 68 | "Geekus", 69 | "Heard and McDonald Islands", 70 | "Carpenter Roth" 71 | ] 72 | }, 73 | { 74 | "guid": "0f7f6732-ca02-45c3-8f2d-85903677b9c1", 75 | "mainImage": "https://unsplash.it/640/360?random", 76 | "title": "Esse ad magna anim non consequat proident", 77 | "summary": "Id fugiat minim velit eu proident deserunt officia ipsum ullamco commodo pariatur.", 78 | "date": "Sat Oct 22 2016 09:58:26 GMT+0000 (UTC)", 79 | "tags": [ 80 | "Companies", 81 | "Hivedom", 82 | "France", 83 | "Jacklyn Henson" 84 | ] 85 | }, 86 | { 87 | "guid": "1e6044da-e7ab-4fdf-9f69-442ef731187c", 88 | "mainImage": "https://unsplash.it/640/360?random", 89 | "title": "Occaecat nostrud magna sit adipisicing", 90 | "summary": "In non ipsum excepteur do deserunt officia veniam dolor magna nisi.", 91 | "date": "Sat Oct 22 2016 13:16:31 GMT+0000 (UTC)", 92 | "tags": [ 93 | "Markets", 94 | "Glasstep", 95 | "Sao Tome and Principe", 96 | "Lawanda Medina" 97 | ] 98 | }, 99 | { 100 | "guid": "3d697f10-af6a-4a40-bf80-856746ffd74c", 101 | "mainImage": "https://unsplash.it/640/360?random", 102 | "title": "Dolor adipisicing dolor esse ad exercitation", 103 | "summary": "Culpa qui qui eiusmod velit deserunt dolor. Velit est excepteur irure elit ex magna.", 104 | "date": "Sun Oct 23 2016 05:09:38 GMT+0000 (UTC)", 105 | "tags": [ 106 | "World", 107 | "Geoform", 108 | "Burkina Faso", 109 | "Lottie Jacobson" 110 | ] 111 | }, 112 | { 113 | "guid": "253f19c4-6fa8-4ddf-a213-9f3c03474262", 114 | "mainImage": "https://unsplash.it/640/360?random", 115 | "title": "Exercitation sunt sunt commodo exercitation", 116 | "summary": "Et excepteur aliquip nisi ex ad eiusmod commodo et cupidatat aute sit commodo qui eu.", 117 | "date": "Sat Oct 22 2016 07:35:39 GMT+0000 (UTC)", 118 | "tags": [ 119 | "Markets", 120 | "Otherway", 121 | "Guam", 122 | "Norris Vega" 123 | ] 124 | }, 125 | { 126 | "guid": "7867d752-cf28-4099-b95e-28269fc7d043", 127 | "mainImage": "https://unsplash.it/640/360?random", 128 | "title": "Fugiat ullamco aliquip culpa id ipsum", 129 | "summary": "In ut cupidatat sit et elit elit eu ad aliqua nulla ullamco ut nulla.", 130 | "date": "Sat Oct 22 2016 15:52:15 GMT+0000 (UTC)", 131 | "tags": [ 132 | "Markets", 133 | "Exoplode", 134 | "Myanmar", 135 | "Day Mccoy" 136 | ] 137 | }, 138 | { 139 | "guid": "bc585179-a31e-402d-8d57-2d10d90756f0", 140 | "mainImage": "https://unsplash.it/640/360?random", 141 | "title": "Mollit anim adipisicing eiusmod tempor", 142 | "summary": "Et in laborum occaecat sunt aliqua nostrud excepteur ea aliquip aliquip.", 143 | "date": "Sat Oct 22 2016 15:55:54 GMT+0000 (UTC)", 144 | "tags": [ 145 | "Companies", 146 | "Centree", 147 | "Svalbard", 148 | "Penny Figueroa" 149 | ] 150 | }, 151 | { 152 | "guid": "e44741cc-24d6-45fd-b95b-1d12e5a7acb8", 153 | "mainImage": "https://unsplash.it/640/360?random", 154 | "title": "Ea aute adipisicing ut labore eu aliquip do", 155 | "summary": "Aute nisi duis velit adipisicing laboris proident ex reprehenderit voluptate elit veniam.", 156 | "date": "Sun Oct 23 2016 01:53:39 GMT+0000 (UTC)", 157 | "tags": [ 158 | "Opinion", 159 | "Kog", 160 | "Djibouti", 161 | "Yolanda Wheeler" 162 | ] 163 | } 164 | ], 165 | "fastft": [ 166 | { 167 | "guid": "237755a7-016b-45ea-b1a2-d08e6ef6b7b3", 168 | "title": "Voluptate reprehenderit mollit commodo ipsum", 169 | "date": "Sun Oct 23 2016 05:22:19 GMT+0000 (UTC)" 170 | }, 171 | { 172 | "guid": "8681b435-2b67-4ea5-aa4d-33380deb76e0", 173 | "title": "Nisi ipsum adipisicing magna consequat", 174 | "date": "Sat Oct 22 2016 16:35:32 GMT+0000 (UTC)" 175 | }, 176 | { 177 | "guid": "8f8e3aeb-4b7b-4e83-953c-5c75201b948a", 178 | "title": "Anim cupidatat in ullamco", 179 | "date": "Sat Oct 22 2016 02:30:20 GMT+0000 (UTC)" 180 | }, 181 | { 182 | "guid": "a92ae544-9ada-4db1-ab85-866e5278f15f", 183 | "title": "Dolore ut excepteur pariatur deserunt id do", 184 | "date": "Sun Oct 23 2016 00:35:20 GMT+0000 (UTC)" 185 | }, 186 | { 187 | "guid": "d14b35c9-f454-4c59-9fb0-03e9bd6875f8", 188 | "title": "Sint deserunt id nisi incididunt cillum voluptate", 189 | "date": "Sat Oct 22 2016 09:58:18 GMT+0000 (UTC)" 190 | } 191 | ] 192 | } 193 | -------------------------------------------------------------------------------- /src/styles/components/_fast-ft.scss: -------------------------------------------------------------------------------- 1 | .FastNews { 2 | background: #fdf8f2; 3 | } 4 | 5 | .FastNews-title { 6 | margin: 0; 7 | padding: 6px 12px; 8 | font-size: 1.25rem; 9 | font-family: sans-serif; 10 | background: #f5dfd9; 11 | color: #cc0033; 12 | 13 | span { 14 | margin-left: -0.25em; 15 | color: #333; 16 | } 17 | } 18 | 19 | .FastNews-list { 20 | margin: 0; 21 | padding-left: 0; 22 | list-style: none; 23 | } 24 | 25 | .FastNews-item { 26 | padding: 8px 12px; 27 | border-top: 1px solid #cec6b9; 28 | } 29 | 30 | .FastNews-link { 31 | color: inherit; 32 | 33 | :first-child > & { 34 | font-size: 1.25rem; 35 | } 36 | } 37 | 38 | .FastNews-date { 39 | display: block; 40 | margin-top: 0.25rem; 41 | color: #cc0033; 42 | font-size: 0.875rem; 43 | font-family: sans-serif; 44 | } 45 | -------------------------------------------------------------------------------- /src/styles/components/_story.scss: -------------------------------------------------------------------------------- 1 | .Story {} 2 | 3 | .Story--picture { 4 | padding: 10px; 5 | background: #e9decf; 6 | } 7 | 8 | .Story-tag { 9 | display: inline-block; 10 | margin-bottom: 0.25rem; 11 | color: #9e2f50; 12 | font-weight: 600; 13 | font-size: 0.875rem; 14 | font-family: sans-serif; 15 | } 16 | 17 | // image placeholder 18 | .Story-cover { 19 | position: relative; 20 | margin-bottom: 0.5rem; 21 | 22 | &:before { 23 | content: ''; 24 | display: block; 25 | padding-top: 56.25%; 26 | } 27 | } 28 | 29 | .Story-coverImage { 30 | position: absolute; 31 | top: 0; 32 | left: 0; 33 | width: 100%; 34 | } 35 | 36 | .Story-content { 37 | // so it doesn't wrap around a cover image 38 | overflow: hidden; 39 | } 40 | 41 | .Story-title { 42 | margin: 0; 43 | font-size: 1.5rem; 44 | font-weight: 600; 45 | line-height: 1.2; 46 | } 47 | 48 | .Story-link { 49 | color: inherit; 50 | } 51 | 52 | .Story-summary { 53 | margin: 0.75rem 0; 54 | font-size: 1rem; 55 | color: #505050; 56 | } 57 | 58 | .Story-date { 59 | display: block; 60 | margin: 0.5rem 0; 61 | color: #8b572a; 62 | font-size: 0.875rem; 63 | font-family: sans-serif; 64 | } 65 | 66 | .Story-related { 67 | margin: 1em 0 0; 68 | padding-left: 0; 69 | list-style: none; 70 | } 71 | 72 | .Story-relatedItem { 73 | margin-bottom: 0.25rem; 74 | 75 | &:before { 76 | content: '➤'; 77 | margin-right: 0.5em; 78 | color: #9e2f50; 79 | font-weight: 600; 80 | } 81 | } 82 | 83 | .Story-relatedLink { 84 | color: inherit; 85 | font-size: 1.125rem; 86 | } 87 | -------------------------------------------------------------------------------- /src/styles/layouts/_grid-headlines.scss: -------------------------------------------------------------------------------- 1 | .Grid--headlines { 2 | 3 | .Story:nth-of-type(1) { 4 | .Story-cover { 5 | display: none; 6 | } 7 | 8 | .Story-title { 9 | font-size: 2.75rem; 10 | line-height: 1; 11 | } 12 | } 13 | 14 | .Story:nth-of-type(2) { 15 | .Story-summary { 16 | display: none; 17 | } 18 | } 19 | 20 | .Story:nth-of-type(6) { 21 | .Story-cover { 22 | display: none; 23 | } 24 | } 25 | 26 | .Story:nth-of-type(6), 27 | .Story:nth-of-type(7) { 28 | .Story-summary { 29 | display: none; 30 | } 31 | } 32 | 33 | .Story:nth-of-type(7) { 34 | .Story-cover { 35 | float: left; 36 | width: 40%; 37 | margin-right: 10px; 38 | } 39 | } 40 | 41 | .Story:nth-of-type(n+8):nth-of-type(-n+11) { 42 | .Story-title { 43 | font-size: 1.25rem; 44 | } 45 | 46 | .Story-cover, 47 | .Story-summary { 48 | display: none; 49 | } 50 | } 51 | 52 | .FastNews { 53 | display: none; 54 | } 55 | 56 | // small screen layout 57 | @media screen and (max-width: 40em) { 58 | .Story { 59 | grid-column: span 12; 60 | } 61 | 62 | .Story:nth-of-type(3), 63 | .Story:nth-of-type(4) { 64 | grid-column: span 6; 65 | } 66 | 67 | .Story:nth-of-type(5) { 68 | .Story-cover { 69 | float: right; 70 | width: 40%; 71 | margin-left: 10px; 72 | } 73 | 74 | .Story-summary { 75 | display: none; 76 | } 77 | } 78 | } 79 | 80 | // medium screen layout 81 | @media screen and (min-width: 40em) and (max-width: 55em) { 82 | .Story:nth-of-type(1), 83 | .Story:nth-of-type(2) { 84 | grid-column: span 6; 85 | } 86 | 87 | .Story:nth-of-type(n+3):nth-of-type(-n+6) { 88 | grid-column: span 4; 89 | } 90 | 91 | .Story:nth-of-type(7) { 92 | grid-column: span 8; 93 | } 94 | 95 | .Story:nth-of-type(n+8):nth-of-type(-n+11) { 96 | grid-column: span 6; 97 | } 98 | } 99 | 100 | // large screen layout 101 | @media screen and (min-width: 55em) { 102 | .Story:nth-of-type(1) { 103 | grid-column: span 4; 104 | } 105 | 106 | .Story:nth-of-type(2) { 107 | grid-column: span 5; 108 | } 109 | 110 | .Story:nth-of-type(3), 111 | .Story:nth-of-type(4), 112 | .Story:nth-of-type(5) { 113 | grid-row: span 5; 114 | grid-column: span 3; 115 | } 116 | 117 | .Story:nth-of-type(6) { 118 | grid-row: span 3; 119 | grid-column: 1 / span 3; 120 | } 121 | 122 | .Story:nth-of-type(7) { 123 | grid-row: span 3; 124 | grid-column: span 6; 125 | } 126 | 127 | .Story:nth-of-type(n+8):nth-of-type(-n+11) { 128 | grid-row: span 2; 129 | grid-column: 10 / span 3; 130 | } 131 | 132 | // fast ft 133 | .FastNews { 134 | display: initial; 135 | grid-row: 1 / span 1; 136 | grid-column: 10 / span 3; 137 | } 138 | } 139 | 140 | } 141 | -------------------------------------------------------------------------------- /src/styles/layouts/_grid.scss: -------------------------------------------------------------------------------- 1 | .Grid { 2 | // declare this a grid container 3 | display: grid; 4 | // gutter between grid items 5 | grid-gap: 20px; 6 | // define 12 equally sized columns (1fr = 1 fraction) 7 | grid-template-columns: repeat(12, 1fr); 8 | // tell the placement algorithm to fill in empty spaces 9 | grid-auto-flow: dense; 10 | 11 | // left and bottom borders between grid items 12 | overflow: hidden; 13 | 14 | > * { 15 | position: relative; 16 | 17 | &:before, 18 | &:after { 19 | content: ''; 20 | position: absolute; 21 | } 22 | 23 | &:before { 24 | top: 0; 25 | bottom: 0; 26 | left: -10px; 27 | border-left: 1px solid #cec6b9; 28 | } 29 | 30 | &:after { 31 | right: 0; 32 | bottom: -10px; 33 | left: 0; 34 | border-bottom: 1px solid #cec6b9; 35 | } 36 | } 37 | } 38 | 39 | // visually hide the title 40 | .Grid-title { 41 | position: absolute; 42 | width: 1px; 43 | height: 1px; 44 | margin: -1px; 45 | clip: rect(0 0 0 0); 46 | } 47 | -------------------------------------------------------------------------------- /src/styles/main.scss: -------------------------------------------------------------------------------- 1 | .Demo { 2 | margin: 0; 3 | font: normal 1em/1.4 'Big Caslon', 'Cambria', 'Times New Roman', serif; 4 | color: #333; 5 | background: #fff1e0; 6 | 7 | a { 8 | text-decoration: none; 9 | border-bottom: 1px dotted transparent; 10 | 11 | &:hover, 12 | &:focus { 13 | border-bottom-color: inherit; 14 | } 15 | } 16 | } 17 | 18 | .Demo-container { 19 | max-width: 80em; 20 | padding: 0 10px; 21 | margin: 0 auto; 22 | } 23 | 24 | .Demo-header { 25 | margin-bottom: 20px; 26 | height: 100px; 27 | border-bottom: 1px solid #cec6b9; 28 | background-image: repeating-linear-gradient( 29 | 45deg, 30 | transparent, 31 | transparent 30px, 32 | rgba(25, 25, 25, 0.1) 30px, 33 | rgba(25, 25, 25, 0.1) 60px 34 | ); 35 | } 36 | 37 | .Demo-footer { 38 | margin-top: 20px; 39 | height: 160px; 40 | border-top: 6px solid #27757b; 41 | color: white; 42 | background: #333; 43 | background-image: repeating-linear-gradient( 44 | 45deg, 45 | transparent, 46 | transparent 30px, 47 | rgba(255, 255, 255, 0.1) 30px, 48 | rgba(255, 255, 255, 0.1) 60px 49 | ); 50 | } 51 | 52 | .Demo-warning { 53 | margin: 10px; 54 | padding: 0.75rem; 55 | border: 2px solid; 56 | text-align: center; 57 | font-family: sans-serif; 58 | color: red; 59 | background: white; 60 | } 61 | 62 | @import 'components/fast-ft'; 63 | @import 'components/story'; 64 | 65 | @import 'layouts/grid'; 66 | @import 'layouts/grid-headlines'; 67 | -------------------------------------------------------------------------------- /src/templates/index.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang="en") 3 | head 4 | meta(charset='utf-8') 5 | meta(name='viewport', content='width=device-width, initial-scale=1') 6 | title FT.com with CSS Grid Layout 7 | link(rel='stylesheet', href='main.css') 8 | script 9 | include partials/support.js 10 | body.Demo 11 | div.Demo-header 12 | main.Demo-container 13 | section.Grid.Grid--headlines 14 | h1.Grid-title Headlines 15 | each item in headlines 16 | include partials/story.pug 17 | include partials/fast-ft.pug 18 | footer.Demo-footer 19 | 20 | -------------------------------------------------------------------------------- /src/templates/partials/fast-ft.pug: -------------------------------------------------------------------------------- 1 | section.FastNews 2 | h2.FastNews-title Fast #[span News] 3 | ol.FastNews-list 4 | each item in fastft 5 | li.FastNews-item 6 | a.FastNews-link(href=`/context/${item.guid}`, rel='bookmark')= item.title 7 | time.FastNews-date(datetime=item.date)= new Date(item.date).toLocaleString() 8 | -------------------------------------------------------------------------------- /src/templates/partials/story.pug: -------------------------------------------------------------------------------- 1 | article.Story(class=`Story--${item.variation || item.tags[0].toLowerCase()}`) 2 | if item.mainImage 3 | div.Story-cover 4 | img.Story-coverImage(src=`${item.mainImage}=${item.guid}`, alt='', role='presentation') 5 | span.Story-tag 6 | case item.tags[0] 7 | when 'Companies' 8 | = item.tags[1] 9 | when 'World' 10 | = item.tags[2] 11 | when 'Opinion' 12 | = item.tags[3] 13 | default 14 | = item.tags[0] 15 | div.Story-content 16 | h2.Story-title 17 | a.Story-link(href=`/content/${item.guid}`)= item.title 18 | p.Story-summary= item.summary 19 | time.Story-date(datetime=item.date)= new Date(item.date).toLocaleString() 20 | 21 | if item.related 22 | ul.Story-related 23 | each scrap in item.related 24 | li.Story-relatedItem 25 | a.Story-relatedLink(href=`/content/${scrap.guid}`)= scrap.title 26 | -------------------------------------------------------------------------------- /src/templates/partials/support.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | var support = window.CSS && CSS.supports('display', 'grid') 3 | 4 | if (!support) { 5 | var p = document.createElement('p') 6 | p.className = 'Demo-warning' 7 | p.innerHTML = 'Your browser does not appear to support grid layout. You may need to enable it.' 8 | document.body.insertBefore(p, document.body.firstChild) 9 | } 10 | }) 11 | --------------------------------------------------------------------------------