├── .eslintrc ├── .gitignore ├── .jshintrc ├── .travis.yml ├── LICENSE ├── README.md ├── assets ├── css │ ├── base │ │ ├── custom-media.css │ │ ├── elements.css │ │ └── variables.css │ ├── components │ │ ├── aligner.css │ │ ├── browser.css │ │ ├── button.css │ │ ├── container.css │ │ ├── demo.css │ │ ├── error.css │ │ ├── feature.css │ │ ├── footer.css │ │ ├── grid.css │ │ ├── header.css │ │ ├── holy-grail.css │ │ ├── image.css │ │ ├── input-add-on.css │ │ ├── media.css │ │ ├── notice.css │ │ ├── section.css │ │ └── site.css │ ├── main.css │ ├── utils │ │ ├── compat.css │ │ ├── media.css │ │ └── size.css │ └── vendor │ │ ├── font-awesome-extensions.css │ │ ├── highlight.css │ │ └── twitter.css └── images │ ├── browser-logos.jpg │ ├── grids.jpg │ ├── holy-grail.jpg │ ├── input-add-ons.jpg │ ├── kitten.jpg │ ├── media-object.jpg │ ├── sticky-footer.jpg │ └── vertical-centering.jpg ├── config.json ├── demos ├── grids.md ├── holy-grail.md ├── input-add-ons.md ├── media-object.md ├── sticky-footer.md └── vertical-centering.md ├── gulpfile.js ├── index.html ├── package-lock.json ├── package.json └── templates ├── default.html ├── footer.html ├── head.html ├── header.html ├── holy-grail.html ├── home.html └── scripts.html /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "browser": true, 5 | "es6": true, 6 | "node": true, 7 | "mocha": true 8 | }, 9 | "globals": { 10 | "browser": false 11 | }, 12 | "extends": [ 13 | "eslint:recommended" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS or Editor folders 2 | .DS_Store 3 | 4 | # npm/yarn files 5 | node_modules 6 | *.log 7 | *.lock 8 | 9 | # Static site output 10 | _tmp/ 11 | solved-by-flexbox/ 12 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "browser": true, 3 | "boss": true, 4 | "esnext": true, 5 | "expr": true, 6 | "node": true, 7 | "quotmark": "single" 8 | } 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: node 3 | before_script: 4 | - npm install -g gulp-cli 5 | script: 6 | - export NODE_ENV=production 7 | - gulp 8 | 9 | deploy: 10 | - provider: pages 11 | skip-cleanup: true 12 | github-token: $GITHUB_TOKEN 13 | local-dir: solved-by-flexbox 14 | on: 15 | branch: zh 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Philip Walton 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Solved by Flexbox](https://magic-akari.github.io/solved-by-flexbox/) 2 | [![Build Status](https://travis-ci.org/magic-akari/solved-by-flexbox.svg?branch=zh)](https://travis-ci.org/magic-akari/solved-by-flexbox) 3 | 4 | 一组示例用于展示曾经难于或无法单独用 CSS 解决的问题, 现在使用 Flexbox 让问题迎刃而解. 5 | 6 | [点击查看](https://magic-akari.github.io/solved-by-flexbox/) 7 | 8 | ## 在本地查看示例 9 | 10 | Solved by Flexbox 页面使用 [Node.js](http://nodejs.org/) 构建. 如果你已经安装 Node.js, 你可以运行下列命令来构建一份本地的拷贝. 11 | 12 | ```sh 13 | # 克隆这个 git 仓库并使用 cd 命令进入克隆的目录. 14 | git clone https://github.com/magic-akari/solved-by-flexbox 15 | cd solved-by-flexbox 16 | 17 | # 安装依赖 18 | npm install 19 | 20 | # 运行, 可以访问 http://localhost:4000 查看 21 | npm start 22 | ``` 23 | 24 | 这个命令会启动一个端口号为 4000 的本地服务. 在浏览器访问 [http://localhost:4000](http://localhost:4000) 即可查看页面. 如果你想使用不同的端口, 可以在 `npm start` 命令后传入参数: 25 | 26 | ```sh 27 | npm start -- -p 8080 28 | ``` 29 | 30 | 此外, 本地启动的服务会监听文件修改, 并自动重新按需构建. 这允许你测试代码, 在浏览器刷新, 并立即查看结果. 31 | 32 | ## 翻译 33 | 34 | 下面的翻译由热心的社区提供: 35 | 36 | * [Chinese](https://magic-akari.github.io/solved-by-flexbox/) 37 | * [Japanese](http://hashrock.github.io/solved-by-flexbox-ja/) 38 | * [Korean](https://hyunseob.github.io/solved-by-flexbox-kr/) 39 | 40 | 请注意, 翻译并非官方提供, 可能随着时间推移而过时. 你可以在 Github 上发送一个 [pull request](https://github.com/philipwalton/solved-by-flexbox/pull/new/master) 或者 [开一个 issue](https://github.com/philipwalton/solved-by-flexbox/issues/new) 提供你的翻译内容的链接. 41 | -------------------------------------------------------------------------------- /assets/css/base/custom-media.css: -------------------------------------------------------------------------------- 1 | @custom-media --break-sm (min-width: 384px); 2 | @custom-media --break-md (min-width: 576px); 3 | @custom-media --break-lg (min-width: 768px); 4 | 5 | @custom-media --high-dppx (-webkit-min-device-pixel-ratio: 1.5), 6 | (min-resolution: 144dpi), (min-resolution: 1.5dppx); 7 | -------------------------------------------------------------------------------- /assets/css/base/elements.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | html { 8 | height: 100%; 9 | color: hsl(0,0%,25%); 10 | font: 400 1em/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 11 | text-rendering: optimizeLegibility; 12 | 13 | text-align: justify; 14 | text-justify: inter-ideograph; 15 | -ms-text-justify: inter-ideograph; 16 | -moz-text-align-last:justify; 17 | -webkit-text-align-last:justify; 18 | } 19 | @media (--high-dppx) { 20 | html { 21 | font-weight: 300; 22 | } 23 | } 24 | 25 | h1 { 26 | font-weight: 300; 27 | font-size: 2em; 28 | -webkit-font-kerning: normal; 29 | letter-spacing: -.015em; 30 | line-height: 1; 31 | margin: .25em 0 .75em; 32 | } 33 | @media (--break-lg) { 34 | h1 { 35 | font-size: 2.5em; 36 | margin: .5em 0 1em; 37 | } 38 | } 39 | 40 | 41 | h2 { 42 | font-size: 1.333em; 43 | font-weight: 600; 44 | margin: 0 0 calc(1.5em/1.333); 45 | } 46 | 47 | h3 { 48 | font-size: 1em; 49 | font-weight: 600; 50 | margin: 0 0 1.5em; 51 | } 52 | 53 | p, 54 | pre { 55 | margin: 0 0 1.5em; 56 | } 57 | 58 | code, 59 | pre { 60 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace 61 | } 62 | 63 | code { 64 | font-size: .9em; 65 | font-weight: normal; 66 | color: #000; 67 | } 68 | 69 | pre > code { 70 | font: inherit; 71 | color: inherit; 72 | } 73 | 74 | a { 75 | border-bottom: 1px dashed hsla(150, 45%, 50%, 0.5); 76 | color: hsl(150, 45%, 50%); 77 | text-decoration: none; 78 | } 79 | a:focus, 80 | a:hover { 81 | border-bottom: 1px solid hsl(150, 45%, 50%); 82 | } 83 | 84 | ol, 85 | ul { 86 | list-style: square; 87 | margin: 0 0 1.5em; 88 | padding: 0 0 0 1.5em; 89 | } 90 | 91 | li { 92 | margin-bottom: 0.333em; 93 | } 94 | 95 | 96 | figure { 97 | margin: 0; 98 | } 99 | 100 | strong { 101 | font-weight: 600; 102 | } 103 | -------------------------------------------------------------------------------- /assets/css/base/variables.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --space: 1.5em; 3 | --space-lg: 2em; 4 | --bg-color: hsl(150, 45%, 50%); 5 | } 6 | -------------------------------------------------------------------------------- /assets/css/components/aligner.css: -------------------------------------------------------------------------------- 1 | .Aligner { 2 | display: flex; 3 | align-items: center; 4 | min-height: 24em; 5 | justify-content: center; 6 | } 7 | 8 | .Aligner-item { 9 | flex: 1; 10 | } 11 | 12 | .Aligner-item--top { 13 | align-self: flex-start; 14 | } 15 | 16 | .Aligner-item--bottom { 17 | align-self: flex-end; 18 | } 19 | 20 | .Aligner-item--fixed { 21 | flex: none; 22 | max-width: 50%; 23 | } 24 | -------------------------------------------------------------------------------- /assets/css/components/browser.css: -------------------------------------------------------------------------------- 1 | .Browser { 2 | font-size: .8em; 3 | text-align: center; 4 | } 5 | 6 | .Browser-image { 7 | height: 64px; 8 | width: 64px; 9 | margin: 0 0.5em 0.5em; 10 | background: url('images/browser-logos.jpg') no-repeat 0 0; 11 | background-size: auto 100%; 12 | } 13 | 14 | .Browser--chrome > .Browser-image { 15 | background-position: 0 0; 16 | } 17 | 18 | .Browser--opera > .Browser-image { 19 | background-position: -64px 0; 20 | } 21 | 22 | .Browser--firefox > .Browser-image { 23 | background-position: -128px 0; 24 | } 25 | 26 | .Browser--safari > .Browser-image { 27 | background-position: -192px 0; 28 | } 29 | 30 | .Browser--ie > .Browser-image { 31 | background-position: -256px 0; 32 | } 33 | 34 | .Browser--edge > .Browser-image { 35 | background-position: -320px 0; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /assets/css/components/button.css: -------------------------------------------------------------------------------- 1 | .Button { 2 | transition: background-color 0.2s; 3 | display: inline-block; 4 | padding: 0.6em 1em; 5 | background: hsla(31, 15%, 50%, 0.15); 6 | color: inherit; 7 | border: 0; 8 | border-radius: 2px; 9 | cursor: pointer; 10 | font-size: 0.8125em; 11 | font-weight: 300; 12 | line-height: normal; 13 | text-decoration: none; 14 | white-space: nowrap; 15 | } 16 | .Button:focus { 17 | outline: thin dotted #666; 18 | text-decoration: none; 19 | } 20 | .Button:active, 21 | .Button:focus, 22 | .Button:hover { 23 | border: 0; 24 | background: hsla(31, 15%, 50%, 0.25); 25 | text-decoration: none; 26 | } 27 | 28 | .Button--action { 29 | background-color: hsl(150, 45%, 50%); 30 | color: #fff; 31 | } 32 | .Button--action:active, 33 | .Button--action:focus, 34 | .Button--action:hover { 35 | background-color: hsl(150, 45%, 40%); 36 | } 37 | 38 | .Button--wide { 39 | padding-right: 1.5em; 40 | padding-left: 1.5em; 41 | } 42 | -------------------------------------------------------------------------------- /assets/css/components/container.css: -------------------------------------------------------------------------------- 1 | .Container { 2 | max-width: 50em; 3 | margin: 0 auto; 4 | } 5 | -------------------------------------------------------------------------------- /assets/css/components/demo.css: -------------------------------------------------------------------------------- 1 | .Demo { 2 | width: 100%; 3 | padding: .8em 1em 0; 4 | background: hsla(31, 15%, 50%, 0.1); 5 | border-radius: 3px; 6 | } 7 | .Demo::after { 8 | content: '\00a0'; /*   */ 9 | display: block; 10 | margin-top: 1em; 11 | height: 0px; 12 | visibility: hidden; 13 | } 14 | 15 | .Demo--spaced { 16 | margin-bottom: var(--space); 17 | } 18 | -------------------------------------------------------------------------------- /assets/css/components/error.css: -------------------------------------------------------------------------------- 1 | .Error { 2 | padding: 1em 1.5em; 3 | background: #c00; 4 | color: #fff; 5 | font-weight: 700; 6 | text-align: center; 7 | } 8 | -------------------------------------------------------------------------------- /assets/css/components/feature.css: -------------------------------------------------------------------------------- 1 | .Feature { 2 | 3 | } 4 | 5 | .Feature-figure { 6 | margin-bottom: 0.75em; 7 | border: 1px solid hsl(0, 0%, 85%); 8 | transition: border-color 0.2s; 9 | } 10 | 11 | .Feature-image { 12 | display: block; 13 | max-width: 100%; 14 | height: auto; 15 | border: 5px solid hsl(0, 100%, 100%); 16 | } 17 | 18 | .Feature-title { 19 | margin: 0 0 0.5em; 20 | color: hsl(0, 0%, 25%); 21 | text-align: center; 22 | transition: color 0.1s; 23 | } 24 | 25 | .Feature-description { 26 | margin: 0 0.75em; 27 | font-size: 0.8em; 28 | } 29 | 30 | .Feature a:active .Feature-figure, 31 | .Feature a:focus .Feature-figure, 32 | .Feature a:hover .Feature-figure { 33 | border-color: hsl(150, 45%, 50%); 34 | } 35 | 36 | .Feature a:active .Feature-title, 37 | .Feature a:focus .Feature-title, 38 | .Feature a:hover .Feature-title { 39 | color: hsl(150, 45%, 50%); 40 | } 41 | -------------------------------------------------------------------------------- /assets/css/components/footer.css: -------------------------------------------------------------------------------- 1 | .Footer { 2 | padding: 1.5rem 1.5rem; 3 | background: gray(25%); 4 | color: gray(60%); 5 | font-size: 0.85em; 6 | overflow-x: hidden; 7 | text-align: center; 8 | } 9 | 10 | .Footer a { 11 | padding-bottom: 1px; 12 | border: 0; 13 | color: gray(90%); 14 | } 15 | .Footer a:focus, 16 | .Footer a:active, 17 | .Footer a:hover { 18 | color: #fff; 19 | text-decoration: underline; 20 | } 21 | 22 | .Footer-credits { 23 | margin: 0; 24 | padding: 0; 25 | } 26 | 27 | .Footer-credit { 28 | display: block; 29 | margin: 0; 30 | } 31 | 32 | .Footer-creditSeparator { 33 | display: none; 34 | } 35 | 36 | /* If loading the social button fails */ 37 | .Footer-social a, 38 | .Footer-social iframe { 39 | display: inline-block; 40 | margin: 0 0 1em; 41 | vertical-align: top; 42 | } 43 | 44 | @media (--break-md) { 45 | .Footer-credit { 46 | display: inline-block; 47 | margin: 0 0.25em; 48 | } 49 | .Footer-creditSeparator { 50 | display: inline-block; 51 | padding: 0 0.25em; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /assets/css/components/grid.css: -------------------------------------------------------------------------------- 1 | .Grid { 2 | display: flex; 3 | flex-wrap: wrap; 4 | list-style: none; 5 | margin: 0; 6 | padding: 0; 7 | } 8 | 9 | .Grid-cell { 10 | flex: 1; 11 | } 12 | 13 | .Grid--flexCells > .Grid-cell { 14 | display: flex; 15 | } 16 | 17 | .Grid--top { 18 | align-items: flex-start; 19 | } 20 | 21 | .Grid--bottom { 22 | align-items: flex-end; 23 | } 24 | 25 | .Grid--center { 26 | align-items: center; 27 | } 28 | 29 | .Grid--justifyCenter { 30 | justify-content: center; 31 | } 32 | 33 | .Grid-cell--top { 34 | align-self: flex-start; 35 | } 36 | 37 | .Grid-cell--bottom { 38 | align-self: flex-end; 39 | } 40 | 41 | .Grid-cell--center { 42 | align-self: center; 43 | } 44 | 45 | .Grid-cell--autoSize { 46 | flex: none; 47 | } 48 | 49 | .Grid--fit > .Grid-cell { 50 | flex: 1; 51 | } 52 | 53 | .Grid--full > .Grid-cell { 54 | flex: 0 0 100%; 55 | } 56 | 57 | .Grid--1of2 > .Grid-cell { 58 | flex: 0 0 50%; 59 | } 60 | 61 | .Grid--1of3 > .Grid-cell { 62 | flex: 0 0 33.3333%; 63 | } 64 | 65 | .Grid--1of4 > .Grid-cell { 66 | flex: 0 0 25%; 67 | } 68 | 69 | @media (--break-sm) { 70 | .small-Grid--fit > .Grid-cell { 71 | flex: 1; 72 | } 73 | .small-Grid--full > .Grid-cell { 74 | flex: 0 0 100%; 75 | } 76 | .small-Grid--1of2 > .Grid-cell { 77 | flex: 0 0 50%; 78 | } 79 | .small-Grid--1of3 > .Grid-cell { 80 | flex: 0 0 33.3333%; 81 | } 82 | .small-Grid--1of4 > .Grid-cell { 83 | flex: 0 0 25%; 84 | } 85 | } 86 | 87 | @media (--break-md) { 88 | .med-Grid--fit > .Grid-cell { 89 | flex: 1; 90 | } 91 | .med-Grid--full > .Grid-cell { 92 | flex: 0 0 100%; 93 | } 94 | .med-Grid--1of2 > .Grid-cell { 95 | flex: 0 0 50%; 96 | } 97 | .med-Grid--1of3 > .Grid-cell { 98 | flex: 0 0 33.3333%; 99 | } 100 | .med-Grid--1of4 > .Grid-cell { 101 | flex: 0 0 25%; 102 | } 103 | } 104 | 105 | @media (--break-lg) { 106 | .large-Grid--fit > .Grid-cell { 107 | flex: 1; 108 | } 109 | .large-Grid--full > .Grid-cell { 110 | flex: 0 0 100%; 111 | } 112 | .large-Grid--1of2 > .Grid-cell { 113 | flex: 0 0 50%; 114 | } 115 | .large-Grid--1of3 > .Grid-cell { 116 | flex: 0 0 33.3333%; 117 | } 118 | .large-Grid--1of4 > .Grid-cell { 119 | flex: 0 0 25%; 120 | } 121 | } 122 | 123 | .Grid--gutters { 124 | margin: -1em 0 1em -1em; 125 | } 126 | .Grid--gutters > .Grid-cell { 127 | padding: 1em 0 0 1em; 128 | } 129 | 130 | .Grid--guttersLg { 131 | margin: -1.5em 0 1.5em -1.5em; 132 | } 133 | .Grid--guttersLg > .Grid-cell { 134 | padding: 1.5em 0 0 1.5em; 135 | } 136 | 137 | .Grid--guttersXl { 138 | margin: -2em 0 2em -2em; 139 | } 140 | .Grid--guttersXl > .Grid-cell { 141 | padding: 2em 0 0 2em; 142 | } 143 | 144 | @media (--break-sm) { 145 | .small-Grid--gutters { 146 | margin: -1em 0 1em -1em; 147 | } 148 | .small-Grid--gutters > .Grid-cell { 149 | padding: 1em 0 0 1em; 150 | } 151 | .small-Grid--guttersLg { 152 | margin: -1.5em 0 1.5em -1.5em; 153 | } 154 | .small-Grid--guttersLg > .Grid-cell { 155 | padding: 1.5em 0 0 1.5em; 156 | } 157 | .small-Grid--guttersXl { 158 | margin: -2em 0 2em -2em; 159 | } 160 | .small-Grid--guttersXl > .Grid-cell { 161 | padding: 2em 0 0 2em; 162 | } 163 | } 164 | 165 | @media (--break-md) { 166 | .med-Grid--gutters { 167 | margin: -1em 0 1em -1em; 168 | } 169 | .med-Grid--gutters > .Grid-cell { 170 | padding: 1em 0 0 1em; 171 | } 172 | .med-Grid--guttersLg { 173 | margin: -1.5em 0 1.5em -1.5em; 174 | } 175 | .med-Grid--guttersLg > .Grid-cell { 176 | padding: 1.5em 0 0 1.5em; 177 | } 178 | .med-Grid--guttersXl { 179 | margin: -2em 0 2em -2em; 180 | } 181 | .med-Grid--guttersXl > .Grid-cell { 182 | padding: 2em 0 0 2em; 183 | } 184 | } 185 | 186 | @media (--break-lg) { 187 | .large-Grid--gutters { 188 | margin: -1em 0 1em -1em; 189 | } 190 | .large-Grid--gutters > .Grid-cell { 191 | padding: 1em 0 0 1em; 192 | } 193 | .large-Grid--guttersLg { 194 | margin: -1.5em 0 1.5em -1.5em; 195 | } 196 | .large-Grid--guttersLg > .Grid-cell { 197 | padding: 1.5em 0 0 1.5em; 198 | } 199 | .large-Grid--guttersXl { 200 | margin: -2em 0 2em -2em; 201 | } 202 | .large-Grid--guttersXl > .Grid-cell { 203 | padding: 2em 0 0 2em; 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /assets/css/components/header.css: -------------------------------------------------------------------------------- 1 | .Header { 2 | padding: 1.5em; 3 | background-color: rgba(147, 128, 108, 0.1); 4 | text-align: center; 5 | } 6 | @media (--break-lg) { 7 | .Header { 8 | padding: 3em 1.5em; 9 | } 10 | } 11 | 12 | .Header-title { 13 | margin: 0 0 0.15em; 14 | font-size: 1.8em; 15 | font-weight: 600; 16 | line-height: 1; 17 | word-spacing: 0.08em; 18 | } 19 | .Header-title i { 20 | font-family: serif; 21 | font-style: italic; 22 | font-weight: 400; 23 | } 24 | .Header-title a { 25 | border: 0; 26 | color: inherit; 27 | font-weight: inherit; 28 | } 29 | .Header-title a:focus, .Header-title a:hover, .Header-title a:active { 30 | text-decoration: none; 31 | } 32 | @media (--break-lg) { 33 | .Header-title { 34 | font-size: 4em; 35 | } 36 | } 37 | 38 | .Header-subTitle { 39 | margin: 0 0 1.5em; 40 | font-size: 0.8em; 41 | font-weight: 300; 42 | white-space: nowrap; 43 | } 44 | @media (--break-lg) { 45 | .Header-subTitle { 46 | margin: 1em 0 1.75em; 47 | font-size: 1.1em; 48 | } 49 | } 50 | 51 | .Header-actions { 52 | display: flex; 53 | align-items: stretch; 54 | flex-direction: column; 55 | font-size: 0.9em; 56 | } 57 | @media (--break-sm) { 58 | .Header-actions { 59 | align-items: center; 60 | flex-direction: row; 61 | justify-content: center; 62 | } 63 | } 64 | @media (--break-lg) { 65 | .Header-actions { 66 | font-size: 1.1em; 67 | } 68 | } 69 | 70 | .Header-button:first-child { 71 | margin: 0 0 1em; 72 | } 73 | @media (--break-sm) { 74 | .Header-button:first-child { 75 | margin: 0 1em 0 0; 76 | } 77 | } 78 | 79 | @media (--break-lg) { 80 | .Header--cozy { 81 | display: flex; 82 | padding: 1.5em; 83 | align-items: center; 84 | } 85 | .Header--cozy .Header-titles { 86 | display: flex; 87 | align-items: baseline; 88 | } 89 | .Header--cozy .Header-title { 90 | font-size: 1.5em; 91 | } 92 | .Header--cozy .Header-subTitle { 93 | margin: 0 0 0 1em; 94 | font-size: 0.8em; 95 | font-weight: 300; 96 | color: gray; 97 | } 98 | .Header--cozy .Header-actions { 99 | flex: 1; 100 | justify-content: flex-end; 101 | font-size: 0.9em; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /assets/css/components/holy-grail.css: -------------------------------------------------------------------------------- 1 | /** 2 | * 1. Avoid the IE 10-11 `min-height` bug. 3 | * 2. Set `flex-shrink` to `0` to prevent some browsers from 4 | * letting these items shrink to smaller than their content's default 5 | * minimum size. See http://bit.ly/1Mn35US for details. 6 | * 3. Use `%` instead of `vh` since `vh` is buggy in older mobile Safari. 7 | */ 8 | 9 | .HolyGrail { 10 | display: flex; 11 | height: 100%; /* 1, 3 */ 12 | flex-direction: column; 13 | } 14 | 15 | .HolyGrail-header, 16 | .HolyGrail-footer { 17 | flex: none; /* 2 */ 18 | } 19 | 20 | .HolyGrail-body { 21 | display: flex; 22 | flex: 1 0 auto; /* 2 */ 23 | flex-direction: column; 24 | padding: var(--space); 25 | } 26 | 27 | .HolyGrail-content { 28 | margin-top: var(--space); 29 | } 30 | 31 | .HolyGrail-nav { 32 | order: -1; 33 | } 34 | 35 | .HolyGrail-nav, 36 | .HolyGrail-ads { 37 | padding: 1em; 38 | border-radius: 3px; 39 | background: rgba(147, 128, 108, 0.1); 40 | } 41 | 42 | @media (--break-lg) { 43 | .HolyGrail-body { 44 | flex-direction: row; 45 | } 46 | .HolyGrail-content { 47 | flex: 1; 48 | padding: 0 var(--space-lg); 49 | margin: 0; 50 | } 51 | .HolyGrail-nav, .HolyGrail-ads { 52 | flex: 0 0 12em; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /assets/css/components/image.css: -------------------------------------------------------------------------------- 1 | .Image { 2 | display: block; 3 | width: 40px; 4 | height: auto; 5 | margin-top: 0.2em; 6 | } 7 | 8 | .Image--tiny { 9 | width: 30px; 10 | } 11 | 12 | @media (--break-md) { 13 | .Image { 14 | width: 70px; 15 | } 16 | .Image--tiny { 17 | width: 40px; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /assets/css/components/input-add-on.css: -------------------------------------------------------------------------------- 1 | .InputAddOn { 2 | display: flex; 3 | margin-bottom: 1.5em; 4 | } 5 | 6 | .InputAddOn-field { 7 | flex: 1; 8 | } 9 | .InputAddOn-field:not(:first-child) { 10 | border-left: 0; 11 | } 12 | .InputAddOn-field:not(:last-child) { 13 | border-right: 0; 14 | } 15 | 16 | .InputAddOn-item { 17 | background-color: rgba(147, 128, 108, 0.1); 18 | color: #666666; 19 | font: inherit; 20 | font-weight: normal; 21 | } 22 | 23 | .InputAddOn-field, 24 | .InputAddOn-item { 25 | border: 1px solid rgba(147, 128, 108, 0.25); 26 | padding: 0.5em 0.75em; 27 | } 28 | .InputAddOn-field:first-child, 29 | .InputAddOn-item:first-child { 30 | border-radius: 2px 0 0 2px; 31 | } 32 | .InputAddOn-field:last-child, 33 | .InputAddOn-item:last-child { 34 | border-radius: 0 2px 2px 0; 35 | } 36 | -------------------------------------------------------------------------------- /assets/css/components/media.css: -------------------------------------------------------------------------------- 1 | .Media { 2 | display: flex; 3 | align-items: flex-start; 4 | margin-bottom: 1em; 5 | } 6 | 7 | .Media-figure { 8 | margin-right: 1em; 9 | } 10 | 11 | .Media-body { 12 | flex: 1; 13 | } 14 | .Media-body, 15 | .Media-body :last-child { 16 | margin-bottom: 0; 17 | } 18 | 19 | .Media-title { 20 | margin: 0 0 .5em; 21 | } 22 | 23 | .Media--center { 24 | align-items: center; 25 | } 26 | 27 | .Media--reverse > .Media-figure { 28 | order: 1; 29 | margin: 0 0 0 1em; 30 | } 31 | -------------------------------------------------------------------------------- /assets/css/components/notice.css: -------------------------------------------------------------------------------- 1 | .Notice { 2 | background-color: hsl(90, 100%, 93%); 3 | color: hsla(0, 0%, 0%, .6); 4 | font-size: .9em; 5 | margin-bottom: var(--space); 6 | padding: 1.2em 1.5em; 7 | } 8 | -------------------------------------------------------------------------------- /assets/css/components/section.css: -------------------------------------------------------------------------------- 1 | .Section { 2 | padding: 0 var(--space); 3 | } 4 | .Section:nth-child(2n) { 5 | background-color: hsla(31, 15%, 50%, 0.1); 6 | overflow: hidden; /* Contain margins. */ 7 | } 8 | .Section::before, 9 | .Section::after { 10 | content: '\00a0'; /*   */ 11 | display: block; 12 | height: 0px; 13 | visibility: hidden; 14 | } 15 | .Section::before { 16 | margin-bottom: var(--space); 17 | } 18 | .Section::after { 19 | margin-top: var(--space); 20 | } 21 | @media (--break-lg) { 22 | .Section { 23 | padding: 0 var(--space-lg); 24 | } 25 | .Section::before { 26 | margin-bottom: var(--space-lg); 27 | } 28 | .Section::after { 29 | margin-top: var(--space-lg); 30 | } 31 | } 32 | 33 | .Section-heading { 34 | text-align: center; 35 | } 36 | 37 | @media (--break-lg) { 38 | .Section-list { 39 | padding: 0; 40 | margin: 0 calc(2 * var(--space-lg)) var(--space-lg); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /assets/css/components/site.css: -------------------------------------------------------------------------------- 1 | /** 2 | * 1. Avoid the IE 10-11 `min-height` bug. 3 | * 2. Set `flex-shrink` to `0` to prevent some browsers from 4 | * letting these items shrink to smaller than their content's default 5 | * minimum size. See http://bit.ly/1Mn35US for details. 6 | * 3. Use `%` instead of `vh` since `vh` is buggy in older mobile Safari. 7 | */ 8 | 9 | .Site { 10 | display: flex; 11 | flex-direction: column; 12 | height: 100%; /* 1, 3 */ 13 | } 14 | 15 | .Site-header, 16 | .Site-footer { 17 | flex: none; /* 2 */ 18 | } 19 | 20 | .Site-content { 21 | flex: 1 0 auto; /* 2 */ 22 | padding: var(--space) var(--space) 0; 23 | width: 100%; 24 | } 25 | .Site-content::after { 26 | content: '\00a0'; /*   */ 27 | display: block; 28 | margin-top: var(--space); 29 | height: 0px; 30 | visibility: hidden; 31 | } 32 | @media (--break-lg) { 33 | .Site-content { 34 | padding-top: var(--space-lg); 35 | } 36 | .Site-content::after { 37 | margin-top: var(--space-lg); 38 | } 39 | } 40 | 41 | .Site-content--full { 42 | padding: 0; 43 | } 44 | .Site-content--full::after { 45 | content: none; 46 | } 47 | -------------------------------------------------------------------------------- /assets/css/main.css: -------------------------------------------------------------------------------- 1 | @import 'normalize.css'; 2 | @import 'suitcss-utils-display'; 3 | @import 'suitcss-utils-text'; 4 | 5 | @import './base/variables'; 6 | @import './base/custom-media'; 7 | @import './base/elements'; 8 | 9 | @import './components/aligner'; 10 | @import './components/browser'; 11 | @import './components/button'; 12 | @import './components/container'; 13 | @import './components/demo'; 14 | @import './components/error'; 15 | @import './components/feature'; 16 | @import './components/footer'; 17 | @import './components/grid'; 18 | @import './components/header'; 19 | @import './components/holy-grail'; 20 | @import './components/image'; 21 | @import './components/input-add-on'; 22 | @import './components/media'; 23 | @import './components/notice'; 24 | @import './components/section'; 25 | @import './components/site'; 26 | 27 | @import './utils/compat'; 28 | @import './utils/media'; 29 | @import './utils/size'; 30 | 31 | @import './vendor/font-awesome-extensions'; 32 | @import './vendor/highlight'; 33 | @import './vendor/twitter'; 34 | -------------------------------------------------------------------------------- /assets/css/utils/compat.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Fixes the min-height bug in IE10-11. 3 | * This class should be added to a container element as described in 4 | * Flexbug #3. See http://bit.ly/1gy8OJS for details. 5 | */ 6 | .u-ieMinHeightBugFix { 7 | display: flex; 8 | flex-direction: column; 9 | } 10 | -------------------------------------------------------------------------------- /assets/css/utils/media.css: -------------------------------------------------------------------------------- 1 | @import '../base/custom-media'; 2 | 3 | .u-full { 4 | width: 100% !important; 5 | flex: none !important; 6 | } 7 | 8 | .u-1of2 { 9 | width: 50% !important; 10 | flex: none !important; 11 | } 12 | 13 | .u-1of3 { 14 | width: 33.3333% !important; 15 | flex: none !important; 16 | } 17 | 18 | .u-2of3 { 19 | width: 66.6667% !important; 20 | flex: none !important; 21 | } 22 | 23 | .u-1of4 { 24 | width: 25% !important; 25 | flex: none !important; 26 | } 27 | 28 | .u-3of4 { 29 | width: 75% !important; 30 | flex: none !important; 31 | } 32 | 33 | @media (--break-sm) { 34 | .u-small-full { 35 | width: 100% !important; 36 | flex: none !important; 37 | } 38 | .u-small-1of2 { 39 | width: 50% !important; 40 | flex: none !important; 41 | } 42 | .u-small-1of3 { 43 | width: 33.3333% !important; 44 | flex: none !important; 45 | } 46 | .u-small-2of3 { 47 | width: 66.6667% !important; 48 | flex: none !important; 49 | } 50 | .u-small-1of4 { 51 | width: 25% !important; 52 | flex: none !important; 53 | } 54 | .u-small-3of4 { 55 | width: 75% !important; 56 | flex: none !important; 57 | } 58 | } 59 | 60 | @media (--break-md) { 61 | .u-med-full { 62 | width: 100% !important; 63 | flex: none !important; 64 | } 65 | .u-med-1of2 { 66 | width: 50% !important; 67 | flex: none !important; 68 | } 69 | .u-med-1of3 { 70 | width: 33.3333% !important; 71 | flex: none !important; 72 | } 73 | .u-med-2of3 { 74 | width: 66.6667% !important; 75 | flex: none !important; 76 | } 77 | .u-med-1of4 { 78 | width: 25% !important; 79 | flex: none !important; 80 | } 81 | .u-med-3of4 { 82 | width: 75% !important; 83 | flex: none !important; 84 | } 85 | } 86 | 87 | @media (--break-lg) { 88 | .u-large-full { 89 | width: 100% !important; 90 | flex: none !important; 91 | } 92 | .u-large-1of2 { 93 | width: 50% !important; 94 | flex: none !important; 95 | } 96 | .u-large-1of3 { 97 | width: 33.3333% !important; 98 | flex: none !important; 99 | } 100 | .u-large-2of3 { 101 | width: 66.6667% !important; 102 | flex: none !important; 103 | } 104 | .u-large-1of4 { 105 | width: 25% !important; 106 | flex: none !important; 107 | } 108 | .u-large-3of4 { 109 | width: 75% !important; 110 | flex: none !important; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /assets/css/utils/size.css: -------------------------------------------------------------------------------- 1 | .u-smaller { 2 | font-size: 0.85em; 3 | } 4 | 5 | .u-bigger { 6 | font-size: 1.2em; 7 | } 8 | -------------------------------------------------------------------------------- /assets/css/vendor/font-awesome-extensions.css: -------------------------------------------------------------------------------- 1 | .icon-big { 2 | font-size: 1.5em; 3 | } 4 | -------------------------------------------------------------------------------- /assets/css/vendor/highlight.css: -------------------------------------------------------------------------------- 1 | @import "highlight.js/styles/github"; 2 | 3 | pre { 4 | border-radius: 3px; 5 | background: hsla(31, 15%, 50%, 0.1); 6 | font-size: 0.85em; 7 | margin-bottom: calc(var(--space)/0.85); 8 | overflow-x: auto; 9 | padding: 1.25em 1.5em; 10 | } 11 | -------------------------------------------------------------------------------- /assets/css/vendor/twitter.css: -------------------------------------------------------------------------------- 1 | .twitter-follow-button { 2 | width: 230px !important; 3 | } 4 | 5 | .twitter-color { 6 | color: #00ACED; 7 | } 8 | -------------------------------------------------------------------------------- /assets/images/browser-logos.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic-akari/solved-by-flexbox/33c8e269e31ba31be2e1ad35f0e86cb7513013e8/assets/images/browser-logos.jpg -------------------------------------------------------------------------------- /assets/images/grids.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic-akari/solved-by-flexbox/33c8e269e31ba31be2e1ad35f0e86cb7513013e8/assets/images/grids.jpg -------------------------------------------------------------------------------- /assets/images/holy-grail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic-akari/solved-by-flexbox/33c8e269e31ba31be2e1ad35f0e86cb7513013e8/assets/images/holy-grail.jpg -------------------------------------------------------------------------------- /assets/images/input-add-ons.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic-akari/solved-by-flexbox/33c8e269e31ba31be2e1ad35f0e86cb7513013e8/assets/images/input-add-ons.jpg -------------------------------------------------------------------------------- /assets/images/kitten.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic-akari/solved-by-flexbox/33c8e269e31ba31be2e1ad35f0e86cb7513013e8/assets/images/kitten.jpg -------------------------------------------------------------------------------- /assets/images/media-object.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic-akari/solved-by-flexbox/33c8e269e31ba31be2e1ad35f0e86cb7513013e8/assets/images/media-object.jpg -------------------------------------------------------------------------------- /assets/images/sticky-footer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic-akari/solved-by-flexbox/33c8e269e31ba31be2e1ad35f0e86cb7513013e8/assets/images/sticky-footer.jpg -------------------------------------------------------------------------------- /assets/images/vertical-centering.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic-akari/solved-by-flexbox/33c8e269e31ba31be2e1ad35f0e86cb7513013e8/assets/images/vertical-centering.jpg -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Solved by Flexbox", 3 | "tagline": "更干净,无奇技淫巧的 CSS", 4 | "description": "A showcase of problems once hard or impossible to solve with CSS alone, now made trivially easy with Flexbox." 5 | } 6 | -------------------------------------------------------------------------------- /demos/grids.md: -------------------------------------------------------------------------------- 1 | --- 2 | template: default.html 3 | title: 更棒,更简洁的栅格系统 4 | excerpt: Flexbox 满足了我们大部分对于栅格系统的需求。尺寸、对齐仅用一两个属性就能搞定。 5 | --- 6 | 7 | 现今大部分栅格系统都使用了两种布局方式中的一种:浮动 (`float`) 或者 內联块 (`inline-block`)。但是它们的初衷均不是真的用于布局 (layout),也因此导致了诸多的问题和限制。 8 | 9 | 10 | 11 | 使用浮动 (float) 需要清除浮动,因此牵连出了一堆布局问题,最臭名昭著的是清除一个元素的浮动有时会强制它出现在一个不相关的页面部分的下边 (例如 [Bootstrap issue](https://github.com/twbs/bootstrap/issues/295#issuecomment-2282969) )。并且,使用清除浮动通常会同时使用 before 和 after 两个伪元素,导致你不能将该伪元素使用于其他用途。 12 | 13 | 14 | 15 | 内联块布局最著名的问题是 [内联块之间空白问题](http://css-tricks.com/fighting-the-space-between-inline-block-elements/), 以及其所有 [解决方案](http://davidwalsh.name/remove-whitespace-inline-block) 都是 [奇技淫巧](https://github.com/suitcss/components-grid/blob/master/lib/grid.css#L30) 和 [恼人](https://twitter.com/thierrykoblentz/status/305152267374428160) 的。 16 | 17 | 18 | 19 | Flexbox 布局不仅结局了这些问题,还开启全新可能性的新世界的大门。 20 | 21 | 22 | 23 | ## Flexbox 栅格系统特性 24 | 25 | 26 | 27 | 栅格系统通常有数不清的尺寸选项,但是通常情况你仅仅想要一个两栏或三栏的栅格系统。既然如此,我们为什么一定要把尺寸属性 (sizing classes) 写到每一个格子 (cell) 里? 28 | 29 | 30 | 31 | 下列是我对于一个理想的栅格系统的标准。幸运的是,Flexbox 布局满足了大部分特性。 32 | 33 | 34 | 35 | - 每一行里的每一个栅格默认都是等宽等高。默认自适应。 36 | - 为了足够灵活,能够添加尺寸属性到单独的栅格中。没有添加的,仍然简单地平分剩下的可用空间。 37 | - 支持响应式布局,可以添加媒体查询到栅格中。 38 | - 每一个栅格可以在垂直方向上置顶,置底,居中。 39 | - 如果让所有栅格拥有一致的大小和对齐方式,在容器上添加属性,子元素能够继承,而不需要无意义的重复。 40 | - 栅格能够任意的嵌套。 41 | 42 | 48 | 49 | ### 基础栅格系统 50 | 51 | 52 | 53 | 下面的栅格没有指定特定的宽度,它们自然的平分每一行的空间并撑满每一个行,并且高度默认都是相等的。 54 | 55 | 56 | 57 |
58 |
59 |
1/2
60 |
61 |
62 |
1/2
63 |
64 |
65 | 66 |
67 |
68 |
1/3
69 |
70 |
71 |
1/3
72 |
73 |
74 |
1/3
75 |
76 |
77 | 78 |
79 |
80 |
1/4
81 |
82 |
83 |
1/4
84 |
85 |
86 |
1/4
87 |
88 |
89 |
1/4
90 |
91 |
92 | 93 |
94 |
95 |
96 | 高度撑满,即使内容没有填满空间。 97 |
98 |
99 | 100 |
101 |
102 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum mollis velit non gravida venenatis. Praesent consequat lectus purus, ut scelerisque velit condimentum eu. Maecenas sagittis ante ut turpis varius interdum. Quisque tellus ipsum, eleifend non ipsum id, suscipit ultricies neque. 103 |
104 |
105 |
106 | 107 | ### 独立的尺寸 108 | 109 | 110 | 111 | 当你的需求不是等宽栅格的时候,可以添加尺寸属性到特定的栅格中。没有尺寸属性的栅格将简单地继续平分剩下的可用空间。 112 | 113 | 114 | 115 | 下边加了 "auto" 标签的栅格没有指定任何尺寸属性。 116 | 117 | 118 | 119 |
120 |
121 |
1/2
122 |
123 |
124 |
auto
125 |
126 |
127 |
auto
128 |
129 |
130 | 131 |
132 |
133 |
auto
134 |
135 |
136 |
1/3
137 |
138 |
139 | 140 |
141 |
142 |
1/4
143 |
144 |
145 |
auto
146 |
147 |
148 |
1/3
149 |
150 |
151 | 152 | ### 响应式 153 | 154 | 155 | 156 | 响应式栅格系统通过添加媒体查询到栅格元素或栅格容器来实现。当满足媒体查询的条件时,栅格系统就能自动调整。 157 | 158 | 159 | 160 | 下边的这些栅格应在低于 `48em` 时撑满一行,调整你的浏览器来查看效果。 161 | 162 | 163 | 164 |
165 |
166 |
Full / Halves
167 |
168 |
169 |
Full / Halves
170 |
171 |
172 |
173 |
174 |
Full / Thirds
175 |
176 |
177 |
Full / Thirds
178 |
179 |
180 |
Full / Thirds
181 |
182 |
183 | 184 | ### 栅格嵌套 185 | 186 | 187 | 188 | 栅格可以无限嵌套于另一个栅格中。 189 | 190 | 191 | 192 |
193 |
194 |
195 |
196 |
197 |
1/3
198 |
199 |
200 |
201 |
202 |
203 |
1/2
204 |
205 |
206 |
1/2
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
1/3
216 |
217 |
218 | 219 | ## 对齐特性 220 | 221 | 222 | 223 | ### 置顶对齐栅格 224 | 225 | 226 | 227 |
228 |
229 |
230 | 我应该置顶对齐。 231 |
232 |
233 |
234 |
235 | Pellentesque sagittis vel erat ac laoreet. Phasellus ac aliquet enim, eu aliquet sem. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed pulvinar porta leo, eu ultricies nunc sollicitudin vitae. Curabitur pulvinar dolor lectus, quis porta turpis ullamcorper nec. Quisque eget varius turpis, quis iaculis nibh. 236 |
237 |
238 |
239 |
240 | 我应该置顶对齐。 241 |
242 |
243 |
244 | 245 | ### 置底对齐栅格 246 | 247 | 248 | 249 |
250 |
251 |
252 | 我应该置底对齐栅格。 253 |
254 |
255 |
256 |
257 | Curabitur pulvinar dolor lectus, quis porta turpis ullamcorper nec. Quisque eget varius turpis, quis iaculis nibh. Ut interdum ligula id metus hendrerit cursus. Integer eu leo felis. Aenean commodo ultrices nunc, sit amet blandit elit gravida in. 258 |
259 |
260 |
261 |
262 | 我应该置底对齐栅格。 263 |
264 |
265 |
266 | 267 | ### 垂直居中栅格 268 | 269 | 270 | 271 |
272 |
273 |
274 | 我应该相对于我右边的格子垂直居中。 275 |
276 |
277 |
278 |
279 | Curabitur pulvinar dolor lectus, quis porta turpis ullamcorper nec. Quisque eget varius turpis, quis iaculis nibh. Ut interdum ligula id metus hendrerit cursus. Integer eu leo felis. Aenean commodo ultrices nunc, sit amet blandit elit gravida in. Sed est ligula, ornare ac nisi adipiscing, iaculis facilisis tellus. Nullam vel facilisis libero. Duis semper lobortis elit, vitae dictum erat.
280 |
281 |
282 | 283 | ### 混合垂直对齐 284 | 285 | 286 | 287 |
288 |
289 |
290 | 我应该置顶对齐。 291 |
292 |
293 |
294 |
295 | Curabitur pulvinar dolor lectus, quis porta turpis ullamcorper nec. Quisque eget varius turpis, quis iaculis nibh. Ut interdum ligula id metus hendrerit cursus. Integer eu leo felis. Aenean commodo ultrices nunc, sit amet blandit elit gravida in. Sed est ligula, ornare ac nisi adipiscing, iaculis facilisis tellus.
296 |
297 |
298 |
299 | 我应该垂直居中。 300 |
301 |
302 |
303 |
304 | 我应该置底对齐。 305 |
306 |
307 |
308 | 309 | ## HTML 代码 310 | 311 | 312 | 313 | ```html 314 |
315 |
316 |
317 |
318 |
319 | ``` 320 | 321 | ## CSS 代码 322 | 323 | 324 | 325 | ### 基础栅格系统 326 | 327 | 328 | 329 | ```css 330 | .Grid { 331 | display: flex; 332 | } 333 | 334 | .Grid-cell { 335 | flex: 1; 336 | } 337 | ``` 338 | 339 | ### 栅格系统修饰属性 340 | 341 | 342 | 343 | ```css 344 | /* With gutters */ 345 | .Grid--gutters { 346 | margin: -1em 0 0 -1em; 347 | } 348 | .Grid--gutters > .Grid-cell { 349 | padding: 1em 0 0 1em; 350 | } 351 | 352 | /* Alignment per row */ 353 | .Grid--top { 354 | align-items: flex-start; 355 | } 356 | .Grid--bottom { 357 | align-items: flex-end; 358 | } 359 | .Grid--center { 360 | align-items: center; 361 | } 362 | 363 | /* Alignment per cell */ 364 | .Grid-cell--top { 365 | align-self: flex-start; 366 | } 367 | .Grid-cell--bottom { 368 | align-self: flex-end; 369 | } 370 | .Grid-cell--center { 371 | align-self: center; 372 | } 373 | ``` 374 | 375 | ### 响应式修饰属性 (移动设备优先) 376 | 377 | 378 | 379 | ```css 380 | /* Base classes for all media */ 381 | .Grid--fit > .Grid-cell { 382 | flex: 1; 383 | } 384 | .Grid--full > .Grid-cell { 385 | flex: 0 0 100%; 386 | } 387 | .Grid--1of2 > .Grid-cell { 388 | flex: 0 0 50%; 389 | } 390 | .Grid--1of3 > .Grid-cell { 391 | flex: 0 0 33.3333%; 392 | } 393 | .Grid--1of4 > .Grid-cell { 394 | flex: 0 0 25%; 395 | } 396 | 397 | /* Small to medium screens */ 398 | @media (min-width: 24em) { 399 | .small-Grid--fit > .Grid-cell { 400 | flex: 1; 401 | } 402 | .small-Grid--full > .Grid-cell { 403 | flex: 0 0 100%; 404 | } 405 | .small-Grid--1of2 > .Grid-cell { 406 | flex: 0 0 50%; 407 | } 408 | .small-Grid--1of3 > .Grid-cell { 409 | flex: 0 0 33.3333%; 410 | } 411 | .small-Grid--1of4 > .Grid-cell { 412 | flex: 0 0 25%; 413 | } 414 | } 415 | 416 | /* Large screens */ 417 | @media (min-width: 48em) { 418 | .large-Grid--fit > .Grid-cell { 419 | flex: 1; 420 | } 421 | .large-Grid--full > .Grid-cell { 422 | flex: 0 0 100%; 423 | } 424 | .large-Grid--1of2 > .Grid-cell { 425 | flex: 0 0 50%; 426 | } 427 | .large-Grid--1of3 > .Grid-cell { 428 | flex: 0 0 33.3333%; 429 | } 430 | .large-Grid--1of4 > .Grid-cell { 431 | flex: 0 0 25%; 432 | } 433 | } 434 | ``` 435 | 436 | 在 Github 中查看这个 demo 中完整的栅格组件 [源代码](https://github.com/magic-akari/solved-by-flexbox/blob/master/assets/css/components/grid.css) 437 | 438 | 439 | -------------------------------------------------------------------------------- /demos/holy-grail.md: -------------------------------------------------------------------------------- 1 | --- 2 | template: holy-grail.html 3 | title: 圣杯布局 4 | excerpt: 这是一个经典的 CSS 布局挑战,历史上出现的方案都没有完美解决。直到 Flexbox 布局的出现,终于成为可能。 5 | --- 6 | 7 | [圣杯布局]() 是典型的 CSS 布局问题,有着众多的解决方案。如果你不熟悉圣杯布局的历史,[这篇文章](http://alistapart.com/article/holygrail) 能够提供很好的总结,并给出了几个众所周知的解决方案。 8 | 9 | 10 | 11 | 圣杯布局由页头 (header),中间部分 (center),页脚 (footer),和三栏组成。中间的一栏是主要内容,左边和右边提供如广告、导航的链接。 12 | 13 | 14 | 15 | 大部分的 CSS 解决方案都是以下列为目标: 16 | 17 | 18 | 19 | - 边栏应流动居中,定宽。 20 | - 中间一栏 (主要内容) 在 HTML 源码中应该首先元素出现。 21 | - 所有栏同高,忽略实际高度。 22 | - 使用的 HTML 标记尽量少。 23 | - 当页面内容不够充满页面时,页脚应“粘”在底部。 24 | 25 | 30 | 31 | 不幸的是,这些自然的需求由于原生 CSS 的限制,当前经典的圣杯布局的解决方案都不能完美满足以上所有的要点。 32 | 33 | 34 | 35 | 有了 Flexbox 布局,终极的解决方案终于成为可能。 36 | 37 | 38 | 39 | ## HTML 代码 40 | 41 | 42 | 43 | ```html 44 | 45 |
46 |
47 |
48 | 49 | 50 |
51 | 52 | 53 | ``` 54 | 55 | ## CSS 代码 56 | 57 | 58 | 59 | 让中间部分撑开并让页脚粘在底部的方法使用了 [粘性页脚](../sticky-footer/) 中相同的技术。唯一的不同点是,圣杯布局的中间部分 (`.HolyGrail-body`) 需要指定 `display:flex` 来控制子元素的布局。 60 | 61 | 62 | 63 | ```css 64 | .HolyGrail { 65 | display: flex; 66 | min-height: 100vh; 67 | flex-direction: column; 68 | } 69 | 70 | .HolyGrail-body { 71 | display: flex; 72 | flex: 1; 73 | } 74 | ``` 75 | 76 | 制造三个等高的,流式居中,定宽的边栏很简单: 77 | 78 | 79 | 80 | ```css 81 | .HolyGrail-content { 82 | flex: 1; 83 | } 84 | 85 | .HolyGrail-nav, 86 | .HolyGrail-ads { 87 | /* 12em is the width of the columns */ 88 | flex: 0 0 12em; 89 | } 90 | 91 | .HolyGrail-nav { 92 | /* put the nav on the left */ 93 | order: -1; 94 | } 95 | ``` 96 | 97 | 98 | 99 | 100 | ### 响应式 101 | 102 | 103 | 104 | 圣杯布局来自于每个人都使用个人计算机冲浪的互联网时期的网页设计,但是随着移动设备的激增,圣杯布局已渐渐没落。 105 | 106 | 107 | 108 | 另一方面,使用 Flexbox 布局,创建一个移动设备优先和移动设备友好版本的圣杯布局很简单。其主旨就是把中间的部分默认指定为 `flex-direction:column` ,然后为拥有更宽屏幕的设备指定 `flex-direction:row` 。 109 | 110 | 111 | 112 | 这里是一个完整版的移动式被优先响应式示例。你可以调整浏览器大小来查看效果。 113 | 114 | 115 | 116 | ```css 117 | .HolyGrail, 118 | .HolyGrail-body { 119 | display: flex; 120 | flex-direction: column; 121 | } 122 | 123 | .HolyGrail-nav { 124 | order: -1; 125 | } 126 | 127 | @media (min-width: 768px) { 128 | .HolyGrail-body { 129 | flex-direction: row; 130 | flex: 1; 131 | } 132 | .HolyGrail-content { 133 | flex: 1; 134 | } 135 | .HolyGrail-nav, 136 | .HolyGrail-ads { 137 | /* 12em is the width of the columns */ 138 | flex: 0 0 12em; 139 | } 140 | } 141 | ``` 142 | 143 | 在 Github 中查看这个 demo 中完整的圣杯组件 [源代码](https://github.com/magic-akari/solved-by-flexbox/blob/master/assets/css/components/holy-grail.css) 144 | 145 | 146 | -------------------------------------------------------------------------------- /demos/input-add-ons.md: -------------------------------------------------------------------------------- 1 | --- 2 | template: default.html 3 | title: 输入附加组件 4 | excerpt: 创建全宽度,流式的输入/按钮组在 CSS 的历史中几乎不可能。有了 Flexbox 布局,一切将会变得更简单。 5 | --- 6 | 7 | 因为输入组件 CSS 的工作方式,几乎不可能在一个元素之前或之后附加另一个元素,并让它宽度自适应地占满剩余空间。 8 | 9 | 10 | 11 | 当前仅有的方法,要么知道输入组件的宽度,要么使用 `display:table-cell` ,后者有着自己的问题,尤其是绝对定位在跨浏览器时遭遇的困难。 12 | 13 | 14 | 15 | 有了 Flexbox 布局,所有的问题都烟消云散,并且代码也极其简单。此外,输入栏和输入附加组件默认同高。 16 | 17 | 18 | 19 |
20 |
21 |

前置附加组件

22 |
23 | 数量 24 | 25 |
26 |
27 | 28 | 29 |
30 |
31 |
32 |

后置附加组件

33 |
34 | 35 | 36 |
37 |
38 | 39 | 40 |
41 |
42 |
43 | 44 | ## 前置附加组件和后置附加组件 45 | 46 | 47 | 48 |
49 |
50 |
51 | 52 | 53 | 54 |
55 |
56 |
57 |
58 | 59 | 60 | 61 |
62 |
63 |
64 | 65 | ## HTML 代码 66 | 67 | 68 | 69 | ```html 70 | 71 |
72 | 73 | 74 |
75 | 76 | 77 |
78 | 79 | 80 |
81 | 82 | 83 |
84 | 85 | 86 | 87 |
88 | ``` 89 | 90 | ## CSS 代码 91 | 92 | 93 | 94 | ```css 95 | .InputAddOn { 96 | display: flex; 97 | } 98 | 99 | .InputAddOn-field { 100 | flex: 1; 101 | /* field styles */ 102 | } 103 | 104 | .InputAddOn-item { 105 | /* item styles */ 106 | } 107 | ``` 108 | 109 | 在 Github 中查看这个 demo 中完整的输入附加组件 [源代码](https://github.com/magic-akari/solved-by-flexbox/blob/master/assets/css/components/input-add-on.css) 110 | 111 | 112 | -------------------------------------------------------------------------------- /demos/media-object.md: -------------------------------------------------------------------------------- 1 | --- 2 | template: default.html 3 | title: 媒体对象 4 | excerpt: 创建含有固定或变化的头像的媒体对象,不用担心溢出(overflow),清除浮动(clearfixing),或者块格式化上下文(block formatting context)等奇技淫巧。 5 | --- 6 | 7 | [媒体对象](http://www.stubbornella.org/content/2010/06/25/the-media-object-saves-hundreds-of-lines-of-code) 是面向对象 CSS 的典型代表 (OOCSS). 它的简单实用让很多 CSS 开发者(包括我自己)转向了 OOCSS 开发方法。 8 | 9 | 10 | 11 | 但是像众多 CSS 布局技巧一样,媒体对象必须求助于各种奇技淫巧来达成目标。 12 | 13 | 14 | 15 | 媒体对象的正文不能出现在头像的下边,通过创建一个 [块格式化上下文(block formatting context)](http://www.stubbornella.org/content/2013/07/31/re-visiting-the-secret-power-of-block-fomatting-context/) 或者使用一个与图片等宽的左外边距(margin)/内边距(padding) 。媒体对象必须清除 body 的浮动,通过指定 `overflow:hidden` 或使用伪元素来达成。 16 | 17 | 18 | 19 | 有了 Flexbox 布局,一切都解决了。附带着,FLexbox 布局还允许我们设置任意设置头像的垂直对齐方式。我们可以轻松地把头像移到右边而不用改一行源代码。 20 | 21 | 22 | 23 | ## 基础示例 24 | 25 | 26 | 27 |
28 |
29 |
30 |
31 | Kitten 32 |
33 |

标准媒体对象

34 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur ac nisl quis massa vulputate adipiscing. Vivamus sit amet risus ligula. Nunc eu pulvinar augue.

35 |
36 |
37 |
38 |
39 |
40 | Kitten 41 |
42 |

标准媒体对象

43 |

Donec imperdiet sem leo, id rutrum risus aliquam vitae. Cras tincidunt porta mauris, vel feugiat mauris accumsan eget.

44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | Kitten 52 |
53 |

逆序媒体对象

54 |

Phasellus vel felis purus. Aliquam consequat pellentesque dui, non mollis erat dictum sit amet. Curabitur non quam dictum, consectetur arcu in, vehicula justo. Donec tortor massa, eleifend nec viverra in, aliquet at eros. Mauris laoreet condimentum mauris, non tempor massa fermentum ut. Integer gravida pharetra cursus. Nunc in suscipit nunc.

55 |
56 |
57 |
58 |
59 |
60 | 61 | ## 无图像 62 | 63 | 64 | 65 |
66 |
67 |
68 |
69 |
70 |
71 |

使用图标

72 |

Donec imperdiet sem leo, id rutrum risus aliquam vitae. Vestibulum ac turpis non lacus dignissim dignissim eu sed dui.

73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |

垂直居中的图标

83 |

Nunc nec fermentum dolor. Duis at iaculis turpis. Sed rutrum elit ac egestas dapibus. Duis nec consequat enim.

84 |
85 |
86 |
87 |
88 |
89 | 90 | ## 嵌套媒体对象 91 | 92 | 93 | 94 |
95 |
96 |
97 |
98 | Kitten 99 |
100 |

媒体对象标题

101 |

Phasellus vel felis purus. Aliquam consequat pellentesque dui, non mollis erat dictum sit amet. Curabitur non quam dictum, consectetur arcu in, vehicula justo.

102 |
103 |
104 |
105 | Kitten 106 |
107 |

108 | Mauris porta arcu id magna adipiscing lacinia at congue lacus. Vivamus blandit quam quis tincidunt egestas. Etiam posuere lectus sed sapien malesuada molestie. 109 |

110 |
111 |
112 |
113 |
114 |
115 | Kitten 116 |
117 |
118 |

Vestibulum ac turpis non lacus dignissim dignissim eu sed dui. Proin a ligula sit amet massa malesuada mattis eu a ante. Nunc porttitor sed quam quis sollicitudin. Vestibulum ac turpis non lacus dignissim dignissim eu sed dui.

119 |
120 | 121 |

Rutrum risus aliquam vitae.

122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | 131 |
132 |
133 |
134 | Kitten 135 |
136 |

媒体对象标题

137 |

Phasellus vel felis purus. Aliquam consequat pellentesque dui, non mollis erat dictum sit amet. Curabitur non quam dictum, consectetur arcu in, vehicula justo. Donec tortor massa, eleifend nec viverra in, aliquet at eros. Mauris laoreet condimentum mauris, non tempor massa fermentum ut.

138 |
139 | 140 |

Donec imperdiet sem leo, id rutrum risus aliquam vitae.

141 |
142 |
143 |
144 |
145 | Kitten 146 |
147 |

148 | Mauris porta arcu id magna adipiscing lacinia at congue lacus. Vivamus blandit quam quis tincidunt egestas. Etiam posuere lectus sed sapien malesuada molestie. Aliquam vitae pharetra dolor. Nullam non mattis nunc. 149 |

150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 | 158 | ## HTML 代码 159 | 160 | 161 | 162 | ```html 163 |
164 | 165 |

166 |
167 | ``` 168 | 169 | ## CSS 代码 170 | 171 | 172 | 173 | ```css 174 | .Media { 175 | display: flex; 176 | align-items: flex-start; 177 | } 178 | 179 | .Media-figure { 180 | margin-right: 1em; 181 | } 182 | 183 | .Media-body { 184 | flex: 1; 185 | } 186 | ``` 187 | 188 | 在 Github 中查看这个 demo 中完整的媒体对象组件 [源代码](https://github.com/magic-akari/solved-by-flexbox/blob/master/assets/css/components/media.css) 189 | 190 | 191 | -------------------------------------------------------------------------------- /demos/sticky-footer.md: -------------------------------------------------------------------------------- 1 | --- 2 | template: default.html 3 | title: 粘性页脚 4 | excerpt: 让你的页脚粘在底部一直以来是一个技巧。如果页脚的高度未知,那么基本上就不可能了。然而这已成为过去。 5 | --- 6 | 7 |
8 | 9 | 点击下边的按钮来隐藏这个页面的内容,注意在页面内容无法填充整个页面时,页脚是如何粘在窗口底部的。 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 | 19 | 当页面内容稀少时,让页脚粘在页面底部,是每一个 Web 开发者在他的生涯中尝试解决过的问题。并且,可以说绝大多数情况,这是一个已被解决的问题。然而 [现存的解决方案](http://ryanfait.com/resources/footer-stick-to-bottom-of-page/) 有一个重大的缺陷 — 如果高度未知,就会失效。 20 | 21 | 22 | 23 | Flexbox 布局可以完美解决这类问题。众所周知, Flexbox 布局经常被用在水平布局中,然而在垂直布局中 Flexbox 布局也格外拿手。你所要做的就是把垂直部分包在 flex 容器中,并选择一个元素可以让它展开以高度自适应。它们会自动地利用容器所有可用空间。 24 | 25 | 26 | 27 | 下边的示例中,容器被设置成窗口的高度,内容被设置成按需要扩展。_(注意:在垂直布局中你需要指定容器的高度,这一点和水平布局的自适应不同。)_ 28 | 29 | 30 | 31 | ## HTML 代码 32 | 33 | 34 | 35 | ```html 36 | 37 |
38 |
39 |
40 | 41 | ``` 42 | 43 | ## CSS 代码 44 | 45 | 46 | 47 | ```css 48 | .Site { 49 | display: flex; 50 | min-height: 100vh; 51 | flex-direction: column; 52 | } 53 | 54 | .Site-content { 55 | flex: 1; 56 | } 57 | ``` 58 | 59 | 在 Github 中查看这个 demo 中完整的粘性页脚组件 [源代码](https://github.com/magic-akari/solved-by-flexbox/blob/master/assets/css/components/site.css) 60 | 61 | 62 | 63 | 64 | 65 | 66 |
67 | 68 | 83 | -------------------------------------------------------------------------------- /demos/vertical-centering.md: -------------------------------------------------------------------------------- 1 | --- 2 | template: default.html 3 | title: 垂直居中 4 | excerpt: 这个经典的问题一直被 CSS hackers 挑战了很多年,历史的解决方案没有一个能够完整地解决。有了 Flexbox 布局,终于成为了可能。 5 | --- 6 | 7 | 一直以来缺乏好的垂直居中的方法,是 CSS 的黑点。 8 | 9 | 10 | 11 | 更糟糕的是,目前的垂直居中的技术晦涩而又反直觉,最直接的选择(比如 `vertical-align:middle`) 从未起过作用。 12 | 13 | 14 | 15 | 目前的[垂直解决方案](http://css-tricks.com/centering-in-the-unknown/) 使用了 从负外边距 到 `display:table-cell` 等荒谬的奇技淫巧,包括全高的伪元素。这些技术有时候能够生效,然而并不是所有情况都能如愿。如果你想垂直居中一个形状不确定,或者子元素不是父元素唯一的子元素呢?如果你能用伪元素居中这种奇技淫巧,但是你又想用伪元素做些其他的事呢? 16 | 17 | 18 | 19 | 用了 Flexbox 布局,不再纠结这些麻烦。你可以任意对齐(垂直或者水平),仅仅设置`align-items`, `align-self`, 和 `justify-content` 这些属性就好。 20 | 21 | 22 | 23 |
24 |
25 |
26 |
27 |

我居中啦!

28 |

This box is both vertically and horizontally centered. Even if the text in this box changes to make it wider or taller, the box will still be centered. Go ahead, give it a try. Just click to edit the text.

29 |
30 |
31 |
32 |
33 | 34 | 不像一些现存的垂直居中技术,Flexbox 垂直居中并不会影响其相邻元素的对齐方式。 35 | 36 | 37 | 38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | 52 | ## HTML 代码 53 | 54 | 55 | 56 | ```html 57 |
58 |
59 |
60 |
61 |
62 | ``` 63 | 64 | ## CSS 代码 65 | 66 | 67 | 68 | ```css 69 | .Aligner { 70 | display: flex; 71 | align-items: center; 72 | justify-content: center; 73 | } 74 | 75 | .Aligner-item { 76 | max-width: 50%; 77 | } 78 | 79 | .Aligner-item--top { 80 | align-self: flex-start; 81 | } 82 | 83 | .Aligner-item--bottom { 84 | align-self: flex-end; 85 | } 86 | ``` 87 | 88 | 在 Github 中查看这个 demo 中完整的垂直居中组件 [源代码](https://github.com/magic-akari/solved-by-flexbox/blob/master/assets/css/components/aligner.css) 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const connect = require("connect"); 2 | const cssnano = require("cssnano"); 3 | const fs = require("fs-extra"); 4 | const frontMatter = require("front-matter"); 5 | const globby = require("globby"); 6 | const gulp = require("gulp"); 7 | const he = require("he"); 8 | const hljs = require("highlight.js"); 9 | const htmlMinifier = require("html-minifier"); 10 | const MarkdownIt = require("markdown-it"); 11 | const nunjucks = require("nunjucks"); 12 | const path = require("path"); 13 | const postcss = require("postcss"); 14 | const atImport = require("postcss-import"); 15 | const cssnext = require("postcss-cssnext"); 16 | const serveStatic = require("serve-static"); 17 | const { argv } = require("yargs"); 18 | 19 | /** 20 | * The output directory for all the built files. 21 | */ 22 | const DEST = "./solved-by-flexbox"; 23 | 24 | /** 25 | * The base public path of the site. 26 | */ 27 | const PUBLIC_PATH = path.join("/", DEST, "/"); 28 | 29 | nunjucks.configure("templates", { autoescape: false, noCache: true }); 30 | 31 | /** 32 | * Renders markdown content as HTML with syntax highlighted code blocks. 33 | * @param {string} content A markdown string. 34 | * @return {string} The rendered HTML. 35 | */ 36 | const renderMarkdown = content => { 37 | const md = new MarkdownIt({ 38 | html: true, 39 | typographer: true, 40 | highlight: (code, lang) => { 41 | code = lang 42 | ? hljs.highlight(lang, code).value 43 | : // Since we're not using highlight.js here, we need to 44 | // espace the html, but we have to unescape first in order 45 | // to avoid double escaping. 46 | he.escape(he.unescape(code)); 47 | 48 | return code; 49 | } 50 | }); 51 | 52 | return md.render(content); 53 | }; 54 | 55 | gulp.task("pages", async () => { 56 | const baseData = await fs.readJSON("./config.json"); 57 | const overrides = { 58 | baseUrl: PUBLIC_PATH, 59 | env: process.env.NODE_ENV || "development" 60 | }; 61 | const site = Object.assign({ demos: [] }, baseData, overrides); 62 | 63 | const processContent = async pagePath => { 64 | const slug = path.basename(pagePath, path.extname(pagePath)); 65 | const permalink = site.baseUrl + (slug === "index" ? "" : "demos/" + slug + "/"); 66 | 67 | const fileContents = await fs.readFile(pagePath, "utf-8"); 68 | const { body, attributes } = frontMatter(fileContents); 69 | 70 | const data = { 71 | site, 72 | page: { 73 | content: body, 74 | slug, 75 | permalink, 76 | ...attributes 77 | } 78 | }; 79 | 80 | if (path.extname(pagePath) == ".md") { 81 | data.page.content = renderMarkdown(data.page.content); 82 | } 83 | data.page.content = nunjucks.renderString(data.page.content, data); 84 | 85 | return data; 86 | }; 87 | 88 | const renderPage = async data => { 89 | let html = nunjucks.render(data.page.template, data); 90 | if (process.env.NODE_ENV === "production") { 91 | html = htmlMinifier.minify(html, { 92 | removeComments: true, 93 | collapseWhitespace: true, 94 | collapseBooleanAttributes: true, 95 | removeAttributeQuotes: true, 96 | removeRedundantAttributes: true, 97 | useShortDoctype: true, 98 | removeEmptyAttributes: true, 99 | minifyJS: true, 100 | minifyCSS: true 101 | }); 102 | } 103 | 104 | const outputPath = path.join(data.page.permalink.slice(1), "index.html"); 105 | await fs.outputFile(outputPath, html); 106 | }; 107 | 108 | const demoPaths = await globby("./demos/**/*"); 109 | for (const demoPath of demoPaths) { 110 | const data = await processContent(demoPath); 111 | 112 | // Add the page data to the site demos. 113 | site.demos.push(data.page); 114 | 115 | await renderPage(data); 116 | } 117 | 118 | const pagePaths = await globby("*.html"); 119 | for (const pagePath of pagePaths) { 120 | const data = await processContent(pagePath); 121 | await renderPage(data); 122 | } 123 | }); 124 | 125 | gulp.task("images", () => { 126 | return gulp.src("./assets/images/**/*").pipe(gulp.dest(path.join(DEST, "images"))); 127 | }); 128 | 129 | gulp.task("css", async () => { 130 | const src = "./assets/css/main.css"; 131 | const css = await fs.readFile(src, "utf-8"); 132 | 133 | const plugins = [ 134 | atImport(), 135 | cssnext({ 136 | browsers: "> 1%, last 2 versions, Safari > 5, ie > 9, Firefox ESR" 137 | }) 138 | ]; 139 | if (process.env.NODE_ENV === "production") { 140 | plugins.push( 141 | cssnano({ 142 | preset: ["default", { discardComments: { removeAll: true } }] 143 | }) 144 | ); 145 | } 146 | 147 | const result = await postcss(plugins).process(css, { from: src }); 148 | await fs.outputFile(path.join(DEST, path.basename(src)), result.css); 149 | }); 150 | 151 | gulp.task("default", gulp.parallel("css", "images", "pages")); 152 | 153 | gulp.task( 154 | "serve", 155 | gulp.series("default", () => { 156 | let port = argv.port || argv.p || 4000; 157 | connect() 158 | .use(serveStatic("./")) 159 | .listen(port); 160 | 161 | gulp.watch("./assets/css/**/*.css", gulp.series("css")); 162 | gulp.watch("./assets/images/*", gulp.series("images")); 163 | gulp.watch(["*.html", "./demos/*", "./templates/*"], gulp.series("pages")); 164 | 165 | console.log(`serving on http://localhost:${port}/solved-by-flexbox`); 166 | }) 167 | ); 168 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | --- 2 | template: home.html 3 | --- 4 | 5 |
6 |
7 |

介绍

8 |

CSS 长期以来缺乏合适的布局机制。 变形,动画,滤镜,对这门语言来说都很有用,但是都没有解决 Web 开发者长期抱怨的主要问题。

9 | 10 |

终于,多亏了 Flexbox 布局,我们有了解决方案。

11 | 12 |

这个页面并不是另一个 CSS 框架。主要目的是展示曾经很困难甚至无法单独用 CSS 解决的问题,现在被 Flexbox 布局轻松解决。随着最近释出的 Internet Explorer 11 和 Safari 6.1,最新的 Flexbox 语法已经被每一个的现代浏览器支持。

13 | 14 |

检查下边的 demo 。查看浏览器的网页审查工具或者深入 源代码 查看,一旦 Flexbox 成为主流,CSS 布局代码将会变得多么的简单。

15 | 16 |
17 |
18 | 19 |
20 |
21 |

展示

22 | 37 |
38 |
39 | 40 |
41 |
42 |

浏览器支持

43 | 44 |
    45 |
  • 46 |
    47 |
    48 | Chrome
    21+ 49 |
    50 |
  • 51 |
  • 52 |
    53 |
    54 | Opera
    12.1+ 55 |
    56 |
  • 57 |
  • 58 |
    59 |
    60 | Firefox
    22+ 61 |
    62 |
  • 63 |
  • 64 |
    65 |
    66 | Safari
    6.1+ 67 |
    68 |
  • 69 |
  • 70 |
    71 |
    72 | IE
    10+ 73 |
    74 |
  • 75 |
  • 76 |
    77 |
    78 | Edge
    All 79 |
    80 |
  • 81 |
82 | 83 |

注意事项和已知问题

84 |
    85 |
  • IE 10 支持 Flexbox 布局,但是当前版本仅支持 Flexbox 的草案版本: (display:flexbox)。
  • 86 | 87 |
  • Safari 6 以及更早的版本支持 原始的 Flexbox 语法, 现在已经被淘汰: (display:box)。
  • 88 | 89 |
  • Firefox 27 以及更早的版本不支持多行 flexbox 。查看 bug 报告 获得更多信息。
  • 90 | 91 |
  • 对于所有浏览器的支持力度,可以查看 caniuse.com/flexbox
  • 92 | 93 |
94 |
95 |
96 | 97 |
98 |
99 |

关于代码

100 |

该页面的所有关于 Flexbox 解决特定问题的示例。都没有被设计用来解决浏览器的兼容性。一些浏览器不完全支持 Flexbox 布局的最新语法,所以,很遗憾,一些兼容性工作是需要的。

101 | 102 |

兼容性工作的代码没有展示在示例中,但是如果你好奇实现的细节,你可以查看源代码。每一个 demo 都有指向其源代码的链接,里边有完整的兼容性代码,以及文档注释,所以不用担心,去看一看吧。

103 | 104 |

Flexbox 布局自动化兼容性工具由 autoprefixer 提供。如果你没使用 autoprefixer 来写 Flexbox 代码,那么,你可能会犯一些可怕的错误。

105 | 106 |

在示例代码和源文件中使用的类名来自于 SUIT CSS,基于 BEM 方法。每个示例包含的可重用的 CSS 组件允许你复制修改适应你自己的项目。每个示例页面提供了各自组件的链接。

107 | 108 |

如果你发现了错误或者想提供一些额外的示例,欢迎在 Github 上开一个 issue 或者提交一个 pull request。

109 | 110 |
111 |
112 |
113 |
114 |

翻译

115 | 116 |

以下翻译由社区热心提供:

117 | 118 | 123 |

请注意,翻译并非官方提供,可能随着时间推移而过时。你可以在 Github 上发送一个 pull request 或者 开一个 issue 提供你的翻译内容的链接。

124 | 125 |
126 |
127 |
128 |
129 |

关于该中文翻译版本

130 |

该文档基于 Solved by Flexbox 原始英文版本的 CC-BY 授权协议,由 阿卡琳 独自翻译。

131 |

欢迎任何关于翻译或其建议。请在 Github 上给我发送 pull request 或者 开一个 issue

132 |
133 |
134 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solved-by-flexbox", 3 | "description": "A showcase of problems once hard or impossible to solve with CSS alone, now made trivially easy with Flexbox.", 4 | "homepage": "https://philipwalton.github.io/solved-by-flexbox", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/philipwalton/solved-by-flexbox.git" 8 | }, 9 | "license": "MIT", 10 | "scripts": { 11 | "build": "gulp", 12 | "start": "gulp serve" 13 | }, 14 | "devDependencies": { 15 | "autoprefixer": "^9.6.1", 16 | "connect": "^3.7.0", 17 | "cssnano": "^4.1.10", 18 | "front-matter": "^3.0.2", 19 | "fs-extra": "^8.1.0", 20 | "globby": "^10.0.1", 21 | "gulp": "^4.0.2", 22 | "he": "^1.2.0", 23 | "highlight.js": "^9.15.9", 24 | "html-minifier": "^4.0.0", 25 | "markdown-it": "^9.0.1", 26 | "normalize.css": "^8.0.1", 27 | "nunjucks": "^3.2.0", 28 | "postcss": "^7.0.17", 29 | "postcss-cssnext": "^3.1.0", 30 | "postcss-import": "^12.0.1", 31 | "serve-static": "^1.14.1", 32 | "suitcss-utils-display": "^1.0.2", 33 | "suitcss-utils-text": "^1.0.0", 34 | "yargs": "^13.3.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /templates/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% include 'head.html' %} 4 | 5 | 10 |
11 |
12 |

{{ page.title }}

13 | {{ page.content }} 14 |
15 |
16 | 21 | {% include 'scripts.html' %} 22 | 23 | 24 | -------------------------------------------------------------------------------- /templates/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | -------------------------------------------------------------------------------- /templates/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% if page.title %}{{ page.title }} — {% endif %}{{ site.title }} — {{ site.tagline }} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | -------------------------------------------------------------------------------- /templates/header.html: -------------------------------------------------------------------------------- 1 |
2 |

Solved by Flexbox

3 |

{{ site.tagline }}

4 |
5 |
6 | 13 |   查看项目源代码 14 | 15 | 22 |   告诉大家 23 | 24 |
25 | -------------------------------------------------------------------------------- /templates/holy-grail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% include 'head.html' %} 4 | 5 |
6 | 9 |
10 |
11 |
12 |

{{ page.title }}

13 | {{ page.content }} 14 |
15 | 18 | 21 |
22 | 27 | {% include 'scripts.html' %} 28 | 29 | 30 | -------------------------------------------------------------------------------- /templates/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% include 'head.html' %} 4 | 5 | 10 |
11 | {{ page.content }} 12 |
13 | 18 | {% include 'scripts.html' %} 19 | 20 | 21 | -------------------------------------------------------------------------------- /templates/scripts.html: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | --------------------------------------------------------------------------------