├── .gitignore ├── 404.md ├── Gemfile ├── README.md ├── _chapters ├── 01-introduction.md ├── 02-semantics.md ├── 03-reuse.md ├── 04-ids.md ├── 05-conventions.md ├── 06-modules.md ├── 07-state.md ├── 08-modifiers.md ├── 09-versioning.md ├── 10-javascript.md └── 11-faqs.md ├── _config.yml ├── _includes ├── chapterList.html ├── chapterNavigation.html ├── favicon.html ├── footer.html ├── head.html ├── header.html ├── navigation.html └── share.html ├── _layouts ├── chapter.html ├── chapters.html ├── default.html └── other.md ├── _pages └── chapters.md ├── android-chrome-144x144.png ├── android-chrome-192x192.png ├── android-chrome-36x36.png ├── android-chrome-48x48.png ├── android-chrome-72x72.png ├── android-chrome-96x96.png ├── apple-touch-icon-114x114.png ├── apple-touch-icon-120x120.png ├── apple-touch-icon-144x144.png ├── apple-touch-icon-152x152.png ├── apple-touch-icon-180x180.png ├── apple-touch-icon-57x57.png ├── apple-touch-icon-60x60.png ├── apple-touch-icon-72x72.png ├── apple-touch-icon-76x76.png ├── apple-touch-icon-precomposed.png ├── apple-touch-icon.png ├── assets ├── css │ └── main.css └── img │ ├── card1.png │ ├── logo.png │ └── logo_small.png ├── atom.xml ├── browserconfig.xml ├── deploy.sh ├── favicon-128.png ├── favicon-16x16.png ├── favicon-196x196.png ├── favicon-32x32.png ├── favicon-96x96.png ├── favicon.ico ├── index.md ├── manifest.json ├── mstile-144x144.png ├── mstile-150x150.png ├── mstile-310x150.png ├── mstile-310x310.png ├── mstile-70x70.png ├── safari-pinned-tab.svg └── sitemap.xml /.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | **/.DS_Store 3 | *.sublime-project 4 | *.sublime-workspace 5 | Gemfile.lock -------------------------------------------------------------------------------- /404.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: other 3 | title: We can't find the page you asked for. Sorry. 4 | --- 5 | 6 | This site is really small, so try visiting the [homepage]({{ site.url }}/index.html). 7 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'github-pages' -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [MaintainableCSS 中文版](https://github.com/owenyang0/maintainablecss-cn) 2 | 3 | MaintainableCSS 是一种哲学,教你如何编写模块化,可扩展性,可维护性的CSS。编写 CSS 不用再去过分担心原有的样式会受你的影响。 4 | 5 | > 在线地址:http://owenyang0.github.io/maintainablecss-cn/ 6 | > 英文原版:http://maintainablecss.com/ 7 | 8 | ### 本地启动 9 | ```bash 10 | bundle install 11 | jeklly build 12 | jekyll serve --baseurl '/maintainablecss-cn' 13 | ``` 14 | 15 | ### 贡献者 16 | * [Owen Yang](https://github.com/owenyang0) 17 | * [Bang Wu](https://github.com/bangwu) 18 | 19 | -------------------------------------------------------------------------------- /_chapters/01-introduction.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: chapter 3 | title: 介绍 4 | section: Preface 5 | permalink: /chapters/introduction/ 6 | description: 介绍MaintainableCSS, 用一种模块化和可扩展的方式来编写CSS. 7 | --- 8 | 9 | *MaintainableCSS* 是一种编写模块化、可扩展和易维护的CSS的架构。 10 | 11 | 在实际情况下,这意味着,作为一个开发者,当我想创建一个新的功能或者修改已有的功能的时候,我不需要担心会使原来的代码变的更糟。 12 | 13 | ## 什么都不需要下载 14 | 15 | *MaintainableCSS* 是不需要下载的。这只是一套帮助你构建大规模或者小规模网站的原则、指南和约定。 16 | 17 | ## 可维护的意义是什么? 18 | 19 | 有一份可维护的代码意味着当你编辑一个模块的样式的时候不需要担心意外的改变的其他模块的代码。我清楚的知道我写出的代码是经过封装的。 20 | 21 | ## 可维护的意义是什么? 22 | 23 | 这意味着, 当CSS代码库的大小增长的时候, 维护这些代码不会有任何困难. 如果你曾经继承了一个大的CSS代码库并且害怕去编辑这些已有的样式,你就会深有感触了。 24 | 25 | ## 模块化的意义是什么? 26 | 27 | 模块是一个特殊的、独立的单元,可以与其他的模块进行组合,以便形成更加复杂的单元。例如在一个客厅,你可以把电视、沙发和墙分别看成模块,这些组合在一起就是一个可以使用的房间。 28 | 29 | 如果你带走其中一个单元,其他的任然能够工作的很好,没有电视你也能坐在沙发上,在一个网站上,页眉、页脚、产品列表和文章,这些都可以考虑为一个模块。 30 | 31 | ## 这适合谁? 32 | 33 | 如果你曾经经历过维护CSS的痛苦,这本书可以帮助你避免常见的问题。无论的你的组是1个人或者是100个人,你都能在这本书上找到有用的建议。如果你的网站正在发展,你更加需要这本书。 34 | 35 | ## 这学起来难吗? 36 | 37 | 我想说的是这很容易学。你可以在20分钟内读完这本书并且在几分钟内使用这些规则。如果你发现了任何错误请及时通知我。 38 | -------------------------------------------------------------------------------- /_chapters/02-semantics.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: chapter 3 | title: 语义化(Semantics) 4 | section: Background 5 | permalink: /chapters/semantics/ 6 | description: Why naming something based on what it is, instead of how it looks or behaves is a cornerstone of writing well architected and maintainable CSS code. 7 | --- 8 | 9 | **概述:** 基于这 *是* 什么命名,而不是基于它 *像* 什么或 *能做* 什么命名。 10 | 11 | ## 长版本解释 12 | 13 | 语义化(semantic)的 HTML 不仅仅关乎我们所使用的元素——你当然知道一个链接应该使用 `` 标签,表格数据应该使用 `` 标签,段落使用 `

` 等等。 14 | 15 | 更重要的是,它和我们所添加的类名(class names)和IDs有关。而类名和IDs为 CSS 和 JavaScript提供额外的机制,让我们更容易去操作和增强 HTML 元素。 16 | 17 | 很容易出现不经过思考而随意添加类名的场景,但现实中命名却又特别重要。 18 | 19 | 20 | > “在计算机科学领域,有两大难题,如何让缓存失效(cache invalidation)和如何给各种东西命名。” 21 |
Phil Karlton, 网景架构师 22 | 23 | 这是由于人只是擅长和人沟通,却不太能理解简短的,不具有语义化的抽象概念。 24 | 25 | ## 类名好坏对比 26 | 27 | 试着找出非语义化和语义化类名的区别... 28 | 29 | 30 |

31 |
32 |
33 | 34 | 这里完全看不出这段 HTML 代码要表达 *什么*。你 *可能* 会说它 *看起来* 怎样(比如应该在小屏幕还是大屏幕上),但也就仅此而已。 35 | 36 | 37 |
38 |
39 |
40 |
41 | 42 | 这段代码就正是我所推崇的。我很清楚地知道这段 HTML 代表着什么。虽然我不知道它看起来应该是怎样的,但我并不在乎,这是 CSS 存在的价值。而语义化的类名对 HTML 和 CSS 甚至 JS 都很有意义。 43 | 44 | 所以,*为什么* 我们应该使用语义化的类名呢? 45 | 46 | ## 因为更容易理解 47 | 48 | 若使用语义化类名,不论你是在修改 HTML 或者 CSS,你都清楚你将造成的影响。而使用视觉化类名(visual class names)的方式,你不得不在每一个元素上写很多类名,最终你可能只是对这些类名有一个模糊的理解,而不清楚它真正的意图是什么。而且,视觉化类名非常难以维护。 49 | 50 | 51 | ## 因为要构建响应式站点 52 | 53 | 一般说来,不同的视图(viewport)会有不同的样式。比如,你可能需要在大屏上浮动(float)一个元素,在小屏不浮动。如果你有一个叫 `.clearfix` 的类名来清理浮动,但在小屏上的效果却和类名不一样,这看起来会不会让人困惑呢? 54 | 55 | 使用语义化的类名,你就会基于 mediea queries 去编写样式,这会让 CSS 更易维护。 56 | 57 | 58 | ## 因为更容易查找 59 | 60 | 如果一个元素是基于其外在表像命名,比如 `.red`, `.clearfix`, 和 `.pull-left` 等,那么这些类名就会像垃圾一样散落在代码库的任何地方——当你搜索一段特定的 HTML 代码的时候,类名不会起任何作用。 61 | 62 | 换句话说,如果你的类名足够语义化,搜索特定代码片段是很简单的事。更常见的是,当你从头搜索你的 HTML(想像一下浏览器上的审查元素)去找类名的时候,查找唯一的 CSS 选择器肯定会快很多。 63 | 64 | 65 | ## 因为不想做无故的回归测试 66 | 67 | 如果你使用描述性的,非语义化的类名,那么当你修改其中一个类名的时候,样式的改变会影响每一个使用这个类名的元素。基于你使用 CSS 的经验,你能保证你的修改不会在其他地方产生不可预知的问题吗? 68 | 69 | 语义化的类名是唯一的,所以当你编辑其中一个的时候,你 *能* 自信地说,你的修改只会影响你想要改变的那个模块,维护起来更简单。 70 | 71 | 72 | ## 因为不用再恐惧更新代码 73 | 74 | 和前一个有关回归测试的那一点有关,当你对修改的代码不够自信的时候,你很有可能会造成 BUG 接着便会由于害怕出错而不再碰那些代码。更可怕的是会造成恶性循环,写很多冗余代码,最后变得越来越不具有可维护性。 75 | 76 | 77 | ## 因为有助于自动化测试 78 | 79 | 自动化功能测试需要定位特定的元素,与其进化交互(输入文本,点击按钮、链接等等),基于这些操作进行相关校验。 80 | 81 | 若你的 HTML 通篇都使用描述性的类名,那么你将不会有一个可靠方式去定位一个特定的元素,更惶论与其交互了。 82 | 83 | 84 | ## 因为为JavaScript提供了有意义的接口 85 | 86 | 就像和自动化测试一样,语义化的类名对JavaScript来说同样有意义。描述性的类名不具有可靠性,不可用于定位相应的模块或组件。 87 | 88 | 89 | ## 因为常规维护的担心 90 | 91 | 若你是基于该元素是什么而命名,你就不必再次修改 HTML 的类名。如,heading 始终是 heading, 你不用管它变成什么样子。 92 | 93 | 样式可能会改变,但你只需要改变你的 CSS。这在另一个方面来说,实际是上松耦合从而提高了可维护性。 94 | 95 | 96 | ## 因为非语义类名调试困难 97 | 98 | 当你调试(debug)一个元素的时候,会出现很多类似的 CSS 选择器,增加了调试的难度。 99 | 100 | 101 | ## 因为标准推荐使用 102 | 103 | HTML5 的规范在 [3.2.5.7](https://www.w3.org/TR/html5/dom.html#classes) 里有说,使用类名属性。 104 | 105 | > "[...] 更鼓励使用能描述内容本质的类名,而不是那些只是描述其外在表像的值。" 106 | 107 | 108 | ## 因为能带来性能的提升 109 | 110 | 这是一个 *非常* 小的优势,因为当你一个元素只有一个类名的时候,你的整个 HTML 代码体积都会更小。而使用描述性的类名,每个元素有无数个类名,结果自然与前者不一样。 111 | 112 | 113 | ## 因为和重用规则有关 114 | 115 | 如果你没有使用语义化类名,你有可能会是误解了重用(reuse)的概念,而误用重用。阅读下章,获得更多。 116 | 117 | 123 | 124 | ## 最后想想语义化 125 | 126 | 语义化的类名是 *MaintainableCSS* 的基石,没有它,一切都没意义。所以,基于是什么命名,其他所有都将受益。 127 | -------------------------------------------------------------------------------- /_chapters/03-reuse.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: chapter 3 | title: Reuse 4 | section: Background 5 | permalink: /chapters/reuse/ 6 | description: Learn why avoding reuse and embracing repetition makes CSS maintenance easier. 7 | --- 8 | 9 | **Summary:** Don't try and reuse styles. Adopt a duplication-first approach. 10 | 11 | > “DRY is often misinterpreted as the necessity to never repeat the exact same thing twice [...]. This is impractical and usually counterproductive, and can lead to forced abstractions, over-thought and [over]-engineered code.“ 12 |
Harry Roberts, CSS Wizardy 13 | 14 | Don't take this the wrong way—MaintainableCSS has various strategies for reuse which I will talk about later. The problem is that trying to reuse the bits *inbetween* the curly braces is problematic. Here's why: 15 | 16 | ## Because styles change based on breakpoints. 17 | 18 | Building responsive sites mean that we style elements differently based on viewport size. Imagine trying to build a 2 column grid that: 19 | 20 | - has 50px and 20px padding on large and small screens respectively. 21 | - has 3em and 2em font-size on large and small screens respectively. 22 | - on small screens each column is stacked below each other. Note: "column" is now misleading. 23 | 24 | With this in mind how can you utilise these atomic class names: `.grid`, `.col`, `.pd50`, `.pd20`, `.fs2` and `fs3` and achieve these specs? 25 | 26 |
27 |
Column 1
28 |
Column 2
29 |
30 | 31 | You can see this just isn't going to work. You now need some crazy class names such as `fs3large`. This is just the tip of iceberg when it comes to maintenance issues. 32 | 33 | Alternatively, take the following semantic mark-up that doesn't attempt to reuse styles: 34 | 35 |
36 |
37 |
38 |
39 | 40 | Ensuring this is styled as specified above, is now a simple task with 6 CSS declarations needed in total, 3 of which reside within media queries. 41 | 42 | ## Because styles change based on states. 43 | 44 | How do you make `` to have padding 18px, a slight border, a background of grey and a text colour as a slightly darker shade of red when it's hovered or focused of active i.e. `:hover`,`:focus`, `:active` etc? 45 | 46 | The short answer is you can't. Try to avoid having to fix self-induced problems. 47 | 48 | ## Because reuse makes debugging more difficult. 49 | 50 | When debugging an element, there will be several applicable CSS selectors playing a part making it noisy. 51 | 52 | ## Because granular styles aren't worth bothering with. 53 | 54 | If you're going to do `
` you may as well do `
` which is more explicit anyway. But we don't want to do this because we don't want to mix concerns. 55 | 56 | ## Because visual class names don't hold much meaning. 57 | 58 | Take `red`. Does this mean a red background? Does this mean red text? Does this mean a red gradient? What tint of red does this mean? 59 | 60 | ## Because updating a "utility" class applies to all instances. 61 | 62 | This sounds good but it isn't. You end up applying changes where you didn't mean to. Think regression. Alternatively, you end up scared to touch this utility class so you end up with `.red2`. Then you end up with redundant code. Obviously this is not fun to maintain. 63 | 64 | ## Because non-semantic class names are hard to find. 65 | 66 | If an element has classes based on how it looks such as `.red`, `.col-lg-4` and `.large`, then these classes will be scattered all over the codebase so searching for "red" will yield many results across the HTML templates, making it hard to find the element in question. 67 | 68 | If you use semantic class names, a search should yield just one result. And if it yields more than one result, then this should indicate a problem that needs dealing with. 69 | 70 | Note: if you have a repeated *component* within a module, then searching might yield several results within 1 file. That is, a module would typically live in a single template. 71 | 72 | ## Because reuse causes bloat. 73 | 74 | If you attempt to reuse every single *rule* you'll end up with classes such as: `red`, `clearfix`, `pull-left`, `grid` which leads to HTML bloat: 75 | 76 |
77 | 78 | Bloat makes it harder to maintain and degrades performance (albeit in a minor way). 79 | 80 | ## Because reuse breaks semantics. 81 | 82 | If you strive to reuse the bits inbetween the curly braces to create "atomic" class names, then you encounter all the problems stated in the chapter about [Semantics](/chapters/semantics/). Read that chapter now, if you haven't already. 83 | 84 | ## What if I really want to reuse a style? 85 | 86 | It is extremely rare, but there are times when it really does make sense to reuse a style. In this case use the comma in your selectors and place it in a well named file. 87 | 88 | For example let's say you wanted a bunch of different modules or components to have red text you might do this: 89 | 90 | /* colours.css */ 91 | 92 | /* red text */ 93 | .someSelector, 94 | .someOtherSelector { 95 | color: red; 96 | } 97 | 98 | Remember though that if any selector deviates, even a little bit, then remove it from the common list and duplicate. You must be very careful with something like this. Do it for convenience, not for performance. Your mileage may vary. 99 | 100 | ## What about mixins? 101 | 102 | CSS preprocessors allow you to create mixins which can be really helpful because they provide the best of both worlds but they should be designed with caution. 103 | 104 | You have to be very careful to update a mixin because it propagates in all instances just like utility classes. It can be problematic to edit and instead you create new mixins that are slightly different causing redundancy and maintenance problems. 105 | 106 | Also, mixins can become very complicated with lots of params, conditionality and large declarations of styles. All of this makes it complicated and complicated is hard to maintain. 107 | 108 | To mitigate, you can make mixins really granular. For example you could have a "red text" mixin which is certainly better. But then again, the declaration of that mixin is basically the same as a declaration of red text—might as well just declare that instead. 109 | 110 | If you need to update it in multiple places, then a search and replace might just do it, depending on your context. And even if you did use a mixin, when red changes to orange, you will have to do a search and replace anyway, because the mixin name will otherwise be misleading. 111 | 112 | This does not mean mixins are "bad"—in fact they can be very helpful. For example, being able to apply *clearfix* rules across different elements at different breakpoints is probably a very helpful thing to do for maintainability. Just make sure to use them with care. 113 | 114 | ## What about performance? 115 | 116 | I don't have stats to hand, but I can very confidently say that it's not wise to practice premature optimisation. Let's say you have a very large CSS codebase (100KB or more). 117 | 118 | Firstly, I *guess* you *might* save yourself a few KB. Secondly, there are alternative paths to improving performance and thirdly, you probably have redundant code due to a lack of maintainability. 119 | 120 | Also consider that one or two images are likely to be far larger than the entire CSS so exerting energy here is probably of little value. 121 | 122 | ## Is this violating DRY principles? 123 | 124 | Attempting to reuse `float: left` as an example, is akin to trying to reuse variable names in different Javascript objects. It's simply not in violation of DRY. 125 | 126 | ## Final thoughts on reuse 127 | 128 | Reuse and DRY are such important principles in software engineering but when it comes to CSS, striving to reuse too much ironically makes maintainance *harder*. However, there are times when reuse and abstraction makes sense which is discussed in later chapters. 129 | -------------------------------------------------------------------------------- /_chapters/04-ids.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: chapter 3 | title: IDs 4 | section: Background 5 | permalink: /chapters/ids/ 6 | description: Learn why using IDs as hooks for styling are problematic and what you should do instead. 7 | --- 8 | 9 | **Summary:** *Don't* use IDs as hooks for styling. 10 | 11 | **Why** shouldn't we use IDs for CSS? 12 | 13 | ## Because of specificity issues. 14 | 15 | [IDs overpower class names](http://www.w3.org/TR/css3-selectors/#specificity) by orders of magnitude. For this reason you can't override an ID selector's style with a class name selector easily. 16 | 17 | This becomes a problem when you need a way to provide additional meaning to the HTML, such as state, something we discuss in a chapter of its own. 18 | 19 | #someModule { 20 | color: red; 21 | } 22 | 23 | .someModule-override { 24 | color: blue; 25 | } 26 | 27 | If you apply the ID and the class name to the element, the colour will always be red. 28 | 29 | .someModule { 30 | color: red; 31 | } 32 | 33 | .someModule-override { 34 | color: blue; 35 | } 36 | 37 | Now the colour will be blue as intended. 38 | 39 | ## But, sometimes an ID is required? 40 | 41 | Sometimes using IDs is necessary. For example a form control is linked to a label by ID. And internal anchors are often bound using IDs too. Both of these improve the User Experience. Use as appropriate for additional behaviour, not for styling. 42 | 43 | ## Final thoughts on IDs 44 | 45 | Avoid IDs as hooks for styling but if you need them for other things use them. As and when you do use IDs, stick to the naming conventions you would use for classes as explained in other chapters. -------------------------------------------------------------------------------- /_chapters/05-conventions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: chapter 3 | title: Conventions 4 | section: Core 5 | permalink: /chapters/conventions/ 6 | description: Learn the simple conventions that MaintainableCSS employs to write modules, components and state. 7 | --- 8 | 9 | Conventions can be a bone of contention amongst engineers, but what matters most is readability and consistency. With that said, *MaintainableCSS* has the following convention: 10 | 11 | /* Square brackets denote optional parts */ 12 | .[-][-] {} 13 | 14 | Here are some real examples pertaining to a "search results" module: 15 | 16 | /* module container/root */ 17 | .searchResults {} 18 | 19 | /* components of a module */ 20 | .searchResults-heading {} 21 | 22 | .searchResults-item {} 23 | 24 | /* state: such as AJAX loading */ 25 | .searchResults-isLoading {} 26 | 27 | Each of these class names are semantic. Module, component and state are all delimitted by dashes. Each bit is written in lowerCamelCase. 28 | 29 | We will see this convention used in all upcoming chapters. -------------------------------------------------------------------------------- /_chapters/06-modules.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: chapter 3 | title: Modules 4 | section: Core 5 | permalink: /chapters/modules/ 6 | description: Learn the differences between modules and components and how to identify them within a design. We'll also code up some example modules together. 7 | --- 8 | 9 | ## What's a module? 10 | 11 | A module is a distinct, independent unit, that can be combined with other modules to form a more complex structure. 12 | 13 | In a living room, you can consider the TV, the sofa and the wall art modules. All coming together to create a useable room. 14 | 15 | If you take one of the units away, the rest still works just fine. I don't need the TV to be able to sit on the sofa etc. 16 | 17 | **In a website each of these can be considered modules:** header, footer, search form, sign up form, shopping basket, article, product list, navigation, homepage promo, archive list etc. 18 | 19 | ## What's a component? 20 | 21 | A module is made up of components. Without the components, the module is incomplete or broken. 22 | 23 | For example a sofa is made up of the frame, upholstry, legs, cushions and back pillows, all of which are required components to allow the sofa to function as designed. 24 | 25 | A logo *module* might consist of copy, an image and a link, each of which are components. Without the image the logo is broken, without the link the logo is incomplete. 26 | 27 | ## Modules vs components 28 | 29 | Sometimes it can be tricky to decide whether something is a component or a module. For example a header is a module and it might contain a logo and a navigation menu as part of it. Are these components or modules? 30 | 31 | Ultimately it doesn't matter too much and you can use your own experience to decide. For me, in a recent project it made sense for the logo to be a component of the header, and the navigation menu to be a module within the header. 32 | 33 | Ultimately, only you understand *your* project requirements and if you get this wrong, changing a component for a module or vice versa is a very easy thing to do. 34 | 35 | ## Creating a module 36 | 37 | Let's build a module together. We're going to build a simplified shopping basket which is made up of a title and some products each of which contain the product title and a remove button. Here is the HTML we might typically use: 38 | 39 |
40 |

Basket

41 |
42 |

Product title

43 |
44 | 45 | 46 |
47 |
48 | 49 | And the selectors for that: 50 | 51 | /* module container */ 52 | .basket {} 53 | 54 | /* components */ 55 | .basket-title {} 56 | .basket-item {} 57 | .basket-productTitle {} 58 | .basket-removeButton {} 59 | 60 | That was straight forward. 61 | 62 | ## Creating a second version of a module 63 | 64 | Now, let's say that during the checkout process there is a similar, cut-down version of the basket—perhaps it has a title of "Order Summary" as opposed to "Your Basket". And perhaps it doesn't have the capability to remove products. 65 | 66 | ### Don't be tempted to reuse 67 | 68 | You might be tempted to try and reuse the basket, but as we have learnt in the chapter about Reuse, this is problematic for many reasons. 69 | 70 | Additionally, your template or partial will require conditional logic to handle the differences. The more conditionality you have, the more complicated it is to touch. And, due to this conditionality, the changes you make to the template might cause regression in a condition you're not currently testing, making it harder to maintain. 71 | 72 | ### Duplicate duplicate duplicate 73 | 74 | *MaintainableCSS* of course, advises to duplicate the module instead. In a recent project, I named the new version `.orderSummary`. There was similarities but just a few differences was enough to duplicate instead of the pain of trying to reuse. 75 | 76 | Finally, notice how with the CSS above, we have ended up with Semantic naming and encapsulated styles, making this very easy to maintain, upgrade or AB test, as and when required without fear of regression elsewhere. 77 | -------------------------------------------------------------------------------- /_chapters/07-state.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: chapter 3 | title: State 4 | section: Core 5 | permalink: /chapters/state/ 6 | description: Learn how to provide different styles to your modules and components based on state, such as showing, hiding and loading. 7 | --- 8 | 9 | Often, particularly with richer user interfaces, we need to style modules or components to look different based on state. States such as *showing*, *hiding*, *active*, *inactive*, *disabled*, *loading*, *loaded* etc. To do this we must communicate this with an additional class name. 10 | 11 | ## Encapsulating state 12 | 13 | Let's say a module is called *myModule*. You could apply an `isActive` class as follows: 14 | 15 |
16 | 17 | But it is likely that `isActive` is going to be used in many different modules, and what it means to be active is different depending on the module, so this breaks the fundamental rules of *MaintainableCSS* i.e. it's not encapsulated to the module in question. 18 | 19 | For this reason, state must be prefixed with the module (or component) it pertains to... 20 | 21 | ## Applying state to a module 22 | 23 | So let's say our module is called *myModule*. 24 | 25 | .myModule {} 26 | 27 | Here are some states we might need to apply to `myModule`. 28 | 29 | .myModule-isDisabled {} 30 | .myModule-isActive {} 31 | .myModule-hasProducts {} 32 | .myModule-isHidden {} 33 | .myModule-isLoading {} 34 | 35 | And the HTML needs to be as follows: 36 | 37 |
38 |

39 | 40 | ## Applying state to a component 41 | 42 | If you wanted to apply state to to just the *title* component, then you would apply `myModule-title-isDisabled` to the title component as follows: 43 | 44 |

45 |

46 | 47 | Phew, that was easy. -------------------------------------------------------------------------------- /_chapters/08-modifiers.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: chapter 3 | title: Modifiers 4 | section: Core 5 | permalink: /chapters/modifiers/ 6 | description: Use modifiers to change appearance based on slight differences. 7 | --- 8 | 9 | Modifiers are similiar to states in that they can change or override the style of a module. This can be useful when modules (or components) are almost identical but have slight differences as designed. 10 | 11 | When this is the case, reusing or abstracting common CSS rules is useful for maintainability. This is best explained with two examples: 12 | 13 | ## Example 1: Different background images 14 | 15 | One recent example I have is for an e-commerce site where each Category page has a header at the top but the background image changes based on the category name as follows: 16 | 17 | 18 |

19 | 20 | 21 |
22 | 23 | The CSS for each header is almost identical except for the modifier overrides: 24 | 25 | .categoryHeader { 26 | padding-top: 50px; 27 | padding-bottom: 50px; 28 | /* etc */ 29 | } 30 | 31 | .categoryHeader-boys { 32 | background-image: url(/path/to/boys.jpg); 33 | } 34 | 35 | .categoryHeader-girls { 36 | background-image: url(/path/to/girls.jpg); 37 | } 38 | 39 | ## Example 2: Different colour buttons 40 | 41 | In the same site we designed Product pages so that depending on the colour of the product, we could optionally configure the background colour of the *Add To Basket* button to match, in the CMS. 42 | 43 | 44 | 45 | 46 | The CSS for the green button is identical except for the background-color as follows: 47 | 48 | .addToBasketButton { 49 | padding: 10px 30px; 50 | text-align: center; 51 | /* etc */ 52 | } 53 | 54 | .addToBasketButton-green { 55 | background-color: green; 56 | } 57 | 58 | Easy. -------------------------------------------------------------------------------- /_chapters/09-versioning.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: chapter 3 | title: Versioning 4 | section: Extras 5 | permalink: /chapters/versioning/ 6 | description: Learn how MaintainableCSS makes it really easy to upgrade and AB test modules for rapidly evolving websites. 7 | --- 8 | 9 | Sometimes versioning modules can be helpful when the features of a website evolve over time. For example you may want to A/B test two versions of a module to see what performs better. Or the website might be going through a brand refresh. 10 | 11 | When you have multiple versions of a module in your codebase, it can be tempting to again reuse the same HTML and CSS to do this. *MaintainableCSS* again dictates that you duplicate and provide a unique name to aid maintainability. 12 | 13 | /* existing module */ 14 | .someModule {} 15 | 16 | /* new version of module */ 17 | .someModuleVariant2 {} 18 | 19 | All you have to do is create two separate modules with a unique module name and you can edit each one independently and in your own time. -------------------------------------------------------------------------------- /_chapters/10-javascript.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: chapter 3 | title: Javascript 4 | section: Extras 5 | permalink: /chapters/javascript/ 6 | description: How to write maintainable CSS and maintainable Javascript at the same time. 7 | --- 8 | 9 | You may want to use Javascript to apply the *same* behaviour to multiple modules (or components). A basic example would be two modules that have the same *isHidden* state which hides the module. 10 | 11 | **How might you do this whilst adhering to MaintainableCSS guidelines and without having to repeat yourself?** 12 | 13 | There are two approaches you can take. 14 | 15 | ## 1. Encapsulating states to the module 16 | 17 | If you have a constructor that is responsible for making an element show (or hide) then consider specifying a class name that pertains to the module during instantiation: 18 | 19 | var module1Collasper = new Collapser(element1, { 20 | cssHideClass: 'moduleA-isHidden' 21 | }); 22 | 23 | var module2Collapser = new Collapser(element2, { 24 | cssHideClass: 'moduleB-isHidden' 25 | }); 26 | 27 | Then reuse the CSS styles as follows: 28 | 29 | /* isHidden */ 30 | .moduleA-isHidden, 31 | .moduleB-isHidden { 32 | display: none; 33 | } 34 | 35 | However, if you find this approach causes maintainability issues for whatever reason then you could try an alternative approach... 36 | 37 | ## 2. Creating a global state class 38 | 39 | If you find the first approach causes maintainability issues then it might be better to define a global state class for reuse across different modules: 40 | 41 | .globalState-isHidden { 42 | display: none; 43 | } 44 | 45 | In this scenario, you no longer need to comma delimit each module state, and you no longer need to specify the module state class during instantiation as the `Collapser` constructor will reference the global class name from within: 46 | 47 | var module1Collasper = new Collapser(element1); 48 | var module2Collasper = new Collapser(element2); 49 | 50 | Whilst this approach might *seem* to be more maintainable due to there being less code to update, it does require thought and care which in turn can be problematic. 51 | 52 | For example it might be that there are other visual differences specific to each module that hang off the *isHidden* class. If there are any differences at all, it may well be better to go with the first approach described above as it's easier to reason about and update without causing unexpected regression. 53 | 54 | -------------------------------------------------------------------------------- /_chapters/11-faqs.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: chapter 3 | title: FAQs 4 | section: Extras 5 | permalink: /chapters/faqs/ 6 | description: Your questions about MaintainableCSS are answered here. 7 | --- 8 | 9 | Can't find your answer here? Raise an issue on [Github](https://github.com/adamsilver/maintainablecss.com/issues/new) and I will get back to you as soon as I can. Thanks! 10 | 11 | ## When should I use this? 12 | 13 | MaintainableCSS is an approach that works well when building long-lived, bespokely designed responsive websites that you want to scale. It's also useful for websites that evolve over time. 14 | 15 | ## What if I don't want to use it? 16 | 17 | If you don't like it, feel free not to use it, or take the bits and pieces that you do like—please tell me though what didn't work and why, as i'd love to know more so that we can learn together. 18 | 19 | ## Isn't this the same as [insert methodology here]? 20 | 21 | These guides are the result of building many different types of websites and have been influenced by many experiences and the many people I have worked with. 22 | 23 | With that said, I think it bares most resemblance to BEM and ECSS, so if you're using those or any other methodology that works for you, stick with it. These guides will be here if and when required. 24 | 25 | ## Can I translate your book? 26 | 27 | It's already been translated to [Japanese](http://coliss.com/articles/build-websites/operation/css/maintainable-css-by-adam.html) and German and Spanish are both on the way. So yes, please get in touch to find out how to do this. 28 | 29 | ## Must I give a class name to every element? 30 | 31 | The short answer is no. 32 | 33 | Most of the time it is better to provide and target elements via a class as it makes your code consistent, easy to reason about, performant and portable. But if you decide to do this: `.module h2` it's not going to be the end of the world. 34 | 35 | Also you may have to do something like that because you might be using Markdown (or a similar constraint) in which case you will *need* to target elements rather than class names as follows: 36 | 37 | .someModule h1 {} 38 | .someModule h2 {} 39 | .someModule p {} 40 | .someModule ul {} 41 | 42 | ## Why must I prefix components with the module name? 43 | 44 | Good question. I actually used to write components without the prefix too but ran into problems... 45 | 46 | The HTML I used to write looked something like this: 47 | 48 |
49 |
50 | 51 | And the CSS looked something like this: 52 | 53 | /* module */ 54 | .basket {} 55 | 56 | /* heading component of basket module */ 57 | .basket .heading {} 58 | 59 | The first problem is that when viewing the HTML, you can't easily differentiate between a module and a component, which makes maintainence a bit harder. 60 | 61 | The second problem is that the `.basket .heading` *component* will incorrectly inherit the styles from the `.heading` *module* which is something we don't want, we want our styles encapsulated and bound to the module. 62 | 63 | Similarly, I recently built a shop where there was a *Delivery & Returns* module and a Delivery & Returns *page* with the following CSS causing problems: 64 | 65 | /* module */ 66 | .productDetails .deliveryAndReturns {} 67 | 68 | /* page */ 69 | .deliveryAndReturns {} 70 | 71 | The page styles intefered with the module styles. 72 | 73 | ## What about common styles used in many places e.g. buttons? 74 | 75 | Depending on your visual design requirements buttons can be problematic because they often have different spacing, floating, and other display rules depending on their location, not to mention media queries. 76 | 77 | As a very *simple* example: in one module a primary button might be floated right within a container that has some text to the left of it. And in another module it might be centered with a fixed width and some small text beneath with `margin-bottom` for spacing. 78 | 79 | It becomes really tricky trying to abstract the common rules because you don't want to end up in a situation where you have to override, or worse that you're worried to update the abstracted set of CSS rules. 80 | 81 | However, if you do decide that abstraction is useful there are two approaches you can take. 82 | 83 | The first is to comma delimit several different buttons to apply the same styles as follows: 84 | 85 | .basket-removeButton, 86 | .another-loginButton, 87 | .another-deleteButton { 88 | /*common styles*/ 89 | } 90 | 91 | The second approach is to make a button into a module: 92 | 93 | .primaryButton { 94 | /*common styles*/ 95 | } 96 | 97 | On a recent project I actually went for something in between. I was building a checkout flow. On each page there was a "continue to next step" button that was identical on each of the pages. There was also a "back to previous step" link so I ended up with this: 98 | 99 | .checkoutActions-continueButton { 100 | /*...*/ 101 | } 102 | 103 | .checkoutActions-backButton { 104 | /*...*/ 105 | } 106 | 107 | This approach meant that I segmented the abstraction to known identical modules, improving maintainability without affecting other similar (but not identical) buttons. 108 | 109 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | name: MaintainableCSS - 一种哲学,教你如何编写模块化,可扩展性,可维护性的CSS。 2 | markdown: kramdown 3 | url: /maintainablecss-cn 4 | include: ['_pages'] 5 | collections: 6 | chapters: 7 | output: true 8 | permalink: /:collection/:title/ 9 | description: MaintainableCSS 是一种哲学,教你如何编写模块化,可扩展性,可维护性的CSS。 -------------------------------------------------------------------------------- /_includes/chapterList.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Chapters

4 |
    5 | {% for chapter in site.chapters %} 6 |
  1. 7 | 10 | {{ chapter.title }} 11 | 12 |
  2. 13 | {% endfor %} 14 |
15 |
16 |
-------------------------------------------------------------------------------- /_includes/chapterNavigation.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {% if page.previous %} 4 | Previous: {{page.previous.title}} 5 | {% endif %} 6 | {% if page.next %} 7 | Next: {{page.next.title}} → 8 | {% endif %} 9 |
10 |
-------------------------------------------------------------------------------- /_includes/favicon.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /_includes/footer.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_includes/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {% if page.description %} 9 | 10 | {% else %} 11 | 12 | {% endif %} 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | {% if page.description %} 23 | 24 | {% else %} 25 | 26 | {% endif %} 27 | 28 | 29 | 30 | 31 | 32 | {% if page.description %} 33 | 34 | {% else %} 35 | 36 | {% endif %} 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | {% include favicon.html %} 45 | 46 | 47 | 57 | 58 | -------------------------------------------------------------------------------- /_includes/header.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | {% include navigation.html %} 6 |
7 |
-------------------------------------------------------------------------------- /_includes/navigation.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_includes/share.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_layouts/chapter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ page.title }} | {{ site.name }} 5 | {% include head.html %} 6 | 7 | 8 | {% include header.html %} 9 | {% include chapterNavigation.html %} 10 |
11 |

{{page.title }}

12 | {{ content }} 13 |
14 | {% include share.html %} 15 | {% include chapterNavigation.html last=true %} 16 | {% include chapterList.html %} 17 | {% include footer.html %} 18 | 19 | -------------------------------------------------------------------------------- /_layouts/chapters.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ page.title }} | {{ site.name }} 5 | {% include head.html %} 6 | 7 | 8 | {% include header.html %} 9 |
10 |
11 | {{ content }} 12 |
13 |
14 | {% include footer.html %} 15 | 16 | 17 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% if page.title %}{{ page.title }} | {% endif %} {{ site.name }} 5 | {% include head.html %} 6 | 7 | 8 | {% include header.html %} 9 | {{ content }} 10 | {% include footer.html %} 11 | 12 | 13 | -------------------------------------------------------------------------------- /_layouts/other.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ page.title }} | {{ site.name }} 5 | {% include head.html %} 6 | 7 | 8 | {% include header.html %} 9 |
10 |

{{page.title }}

11 | {{ content }} 12 |
13 | {% include footer.html %} 14 | 15 | -------------------------------------------------------------------------------- /_pages/chapters.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: chapters 3 | id: chapters 4 | permalink: /chapters/ 5 | title: "Chapters" 6 | --- 7 | 8 | {% assign prefaceChapters = site.chapters | where:'section', 'Preface' %} 9 | {% assign backgroundChapters = site.chapters | where:'section', 'Background' %} 10 | {% assign coreChapters = site.chapters | where:'section', 'Core' %} 11 | {% assign extraChapters = site.chapters | where:'section', 'Extras' %} 12 | 13 | # Chapters 14 | 15 | ## Preface 16 | 17 |
    18 | {% for chapter in prefaceChapters %} 19 |
  1. {{ chapter.title }}
  2. 20 | {% endfor %} 21 |
22 | 23 | ## Background 24 | 25 | {% assign backgroundStart = prefaceChapters.size | plus: 1 %} 26 | 27 |
    28 | {% for chapter in backgroundChapters %} 29 |
  1. {{ chapter.title }}
  2. 30 | {% endfor %} 31 |
32 | 33 | ## Core 34 | 35 | {% assign coreStart = backgroundStart | plus: backgroundChapters.size %} 36 | 37 |
    38 | {% for chapter in coreChapters %} 39 |
  1. {{ chapter.title }}
  2. 40 | {% endfor %} 41 |
42 | 43 | ## Extras 44 | 45 | {% assign extrasStart = coreStart | plus: coreChapters.size %} 46 | 47 |
    48 | {% for chapter in extraChapters %} 49 |
  1. {{ chapter.title }}
  2. 50 | {% endfor %} 51 |
-------------------------------------------------------------------------------- /android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/android-chrome-144x144.png -------------------------------------------------------------------------------- /android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/android-chrome-192x192.png -------------------------------------------------------------------------------- /android-chrome-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/android-chrome-36x36.png -------------------------------------------------------------------------------- /android-chrome-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/android-chrome-48x48.png -------------------------------------------------------------------------------- /android-chrome-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/android-chrome-72x72.png -------------------------------------------------------------------------------- /android-chrome-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/android-chrome-96x96.png -------------------------------------------------------------------------------- /apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/apple-touch-icon.png -------------------------------------------------------------------------------- /assets/css/main.css: -------------------------------------------------------------------------------- 1 | /********************************************************** 2 | * General 3 | **********************************************************/ 4 | 5 | * { 6 | margin: 0; 7 | padding: 0; 8 | } 9 | 10 | body { 11 | font-family: 'helvetica neue', helvetica, arial, sans-serif; 12 | text-rendering: optimizeLegibility; 13 | -webkit-font-smoothing: antialiased; 14 | font-size: 62.5%; 15 | } 16 | 17 | a:link, 18 | a:visited { 19 | color: #001F3F; 20 | } 21 | 22 | a:hover, 23 | a:focus { 24 | text-decoration: none; 25 | } 26 | 27 | /********************************************************** 28 | * Footer 29 | **********************************************************/ 30 | 31 | .footer { 32 | background-color: #001F3F; 33 | padding: 20px; 34 | overflow: hidden; 35 | } 36 | 37 | .footer-inner { 38 | max-width: 700px; 39 | margin: 0 auto; 40 | text-align: center; 41 | line-height: 1.4; 42 | } 43 | 44 | .footer p { 45 | color: #fff; 46 | font-size: 1.5em; 47 | } 48 | 49 | .footer a { 50 | color: #fff; 51 | } 52 | 53 | /********************************************************** 54 | * Header 55 | **********************************************************/ 56 | 57 | .header { 58 | background-color: #eee; 59 | } 60 | 61 | .header-inner { 62 | overflow: hidden; 63 | padding: 20px; 64 | max-width: 700px; 65 | margin: 0 auto; 66 | } 67 | 68 | @media(min-width: 320px) { 69 | .header-inner { 70 | padding: 10px 20px; 71 | } 72 | } 73 | 74 | /********************************************************** 75 | * Logo 76 | **********************************************************/ 77 | 78 | .logo { 79 | font-size: 2em; 80 | text-align: center; 81 | margin-bottom: 20px; 82 | font-weight: bold; 83 | } 84 | 85 | @media(min-width: 280px) { 86 | .logo { 87 | float: left; 88 | margin-bottom: 0; 89 | font-size: 1.5em; 90 | font-weight: normal; 91 | margin-top: 1px; 92 | } 93 | } 94 | 95 | .logo a img { 96 | border: none; 97 | } 98 | 99 | /********************************************************** 100 | * Navigation 101 | **********************************************************/ 102 | 103 | .navigation { 104 | font-size: 1.5em; 105 | text-align: center; 106 | } 107 | 108 | @media(min-width: 280px) { 109 | .navigation { 110 | float: right; 111 | margin-top: 10px; 112 | } 113 | } 114 | 115 | .navigation a { 116 | margin-left: 3px; 117 | margin-right: 3px; 118 | text-decoration: none; 119 | color: #001F3F; 120 | } 121 | 122 | @media(min-width: 360px) { 123 | .navigation a { 124 | margin-left: 7px; 125 | margin-right: 7px; 126 | } 127 | } 128 | 129 | .navigation a:hover, 130 | .navigation a:active { 131 | color: #7FDBFF; 132 | } 133 | 134 | a.navigation-isActive { 135 | font-weight: bold; 136 | } 137 | 138 | /********************************************************** 139 | * Content 140 | **********************************************************/ 141 | 142 | .content { 143 | padding-top: 40px; 144 | padding-bottom: 1px; 145 | } 146 | 147 | .content h1 { 148 | font-size: 3em; 149 | line-height: 1.2em; 150 | max-width: 700px; 151 | margin-left: auto; 152 | margin-right: auto; 153 | padding: 0 20px 20px; 154 | color: #001F3F; 155 | } 156 | 157 | @media(min-width: 600px) { 158 | .content h1 { 159 | font-size: 4.5em; 160 | } 161 | } 162 | 163 | .content h2 { 164 | font-size: 2.2em; 165 | line-height: 1.2em; 166 | max-width: 700px; 167 | margin-left: auto; 168 | margin-right: auto; 169 | margin-bottom: 10px; 170 | padding: 0 20px; 171 | color: #001F3F; 172 | } 173 | 174 | @media(min-width: 600px) { 175 | .content h2 { 176 | font-size: 2.5em; 177 | margin-bottom: 15px; 178 | } 179 | } 180 | 181 | .content h3 { 182 | font-size: 1.8em; 183 | line-height: 1.2em; 184 | max-width: 700px; 185 | margin-left: auto; 186 | margin-right: auto; 187 | margin-bottom: 10px; 188 | padding: 0 20px; 189 | color: #001F3F; 190 | } 191 | 192 | @media(min-width: 600px) { 193 | .content h3 { 194 | font-size: 2.2em; 195 | margin-bottom: 15px; 196 | } 197 | } 198 | 199 | .content p { 200 | font-size: 1.8em; 201 | line-height: 1.7em; 202 | max-width: 700px; 203 | margin-left: auto; 204 | margin-right: auto; 205 | margin-bottom: 30px; 206 | padding: 0 20px 10px; 207 | color: #001F3F; 208 | } 209 | 210 | @media(min-width: 600px) { 211 | .content p { 212 | font-size: 2.2em; 213 | margin-bottom: 45px; 214 | } 215 | } 216 | 217 | .content ol, 218 | .content ul { 219 | max-width: 700px; 220 | margin-left: auto; 221 | margin-right: auto; 222 | margin-bottom: 30px; 223 | padding: 0 20px 10px; 224 | color: #001F3F; 225 | } 226 | 227 | @media(min-width: 600px) { 228 | .content ol, 229 | .content ul { 230 | margin-bottom: 45px; 231 | } 232 | } 233 | 234 | .content ol li, 235 | .content ul li { 236 | font-size: 1.8em; 237 | line-height: 1.7em; 238 | margin-left: 30px; 239 | } 240 | 241 | @media(min-width: 600px) { 242 | .content ol li, 243 | .content ul li { 244 | font-size: 2.2em; 245 | } 246 | } 247 | 248 | .content blockquote { 249 | font-style: italic; 250 | max-width: 700px; 251 | margin-left: auto; 252 | margin-right: auto; 253 | margin-bottom: 30px; 254 | padding: 0 20px; 255 | color: #001F3F; 256 | } 257 | 258 | .content blockquote cite { 259 | font-weight: bold; 260 | } 261 | 262 | .content p code { 263 | background: #ddd; 264 | font-size: 1.3em; 265 | color: #001F3F; 266 | } 267 | 268 | .content pre { 269 | font-family: Monaco,'Courier New','Courier',monospace; 270 | font-size: 1.9em; 271 | background-color: #7FDBFF; 272 | margin-bottom: 30px; 273 | padding: 20px; 274 | white-space: pre-wrap; /* css-3 */ 275 | white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ 276 | white-space: -pre-wrap; /* Opera 4-6 */ 277 | white-space: -o-pre-wrap; /* Opera 7 */ 278 | word-wrap: break-word; /* Internet Explorer 5.5+ */ 279 | max-width: 760px; 280 | margin-left: auto; 281 | margin-right: auto; 282 | } 283 | 284 | @media(min-width: 600px) { 285 | .content pre { 286 | font-size: 2.6em; 287 | margin-bottom: 45px; 288 | } 289 | } 290 | 291 | /********************************************************** 292 | * Chapter navigation 293 | **********************************************************/ 294 | 295 | .chapterNavigation { 296 | font-size: 1.5em; 297 | overflow: hidden; 298 | background-color: #001F3F; 299 | } 300 | 301 | .chapterNavigation-last { 302 | margin-bottom: 10px; 303 | } 304 | 305 | .chapterNavigation-inner { 306 | overflow: hidden; 307 | max-width: 700px; 308 | padding: 20px; 309 | margin: 0 auto; 310 | } 311 | 312 | a.chapterNavigation-previous:link, 313 | a.chapterNavigation-previous:visited { 314 | float: left; 315 | text-decoration: none; 316 | color: #fff; 317 | } 318 | 319 | a.chapterNavigation-next:link, 320 | a.chapterNavigation-next:visited { 321 | float: right; 322 | text-decoration: none; 323 | color: #fff; 324 | } 325 | 326 | a.chapterNavigation-previous:hover, 327 | a.chapterNavigation-next:hover, 328 | a.chapterNavigation-previous:active, 329 | a.chapterNavigation-next:active { 330 | color: #7FDBFF; 331 | } 332 | 333 | .chapterNavigation-label { 334 | position: absolute; 335 | left: -999em; 336 | } 337 | 338 | @media(min-width: 360px) { 339 | .chapterNavigation-label { 340 | position: static; 341 | left: auto; 342 | } 343 | } 344 | 345 | /********************************************************** 346 | * Hero 347 | **********************************************************/ 348 | 349 | .hero { 350 | padding-left: 20px; 351 | padding-right: 20px; 352 | padding-top: 30px; 353 | padding-bottom: 50px; 354 | background-color: #7FDBFF; 355 | background-color: #001F3F; 356 | } 357 | 358 | @media(min-width: 600px) { 359 | .hero { 360 | padding-top: 60px; 361 | padding-bottom: 90px; 362 | } 363 | } 364 | 365 | .hero-logo { 366 | display: block; 367 | margin: 0 auto 10px; 368 | height: 180px; 369 | width: 180px; 370 | } 371 | 372 | @media(min-width: 500px) { 373 | .hero-logo { 374 | width: 250px; 375 | height: 250px; 376 | } 377 | } 378 | 379 | .hero h1 { 380 | font-size: 3em; 381 | line-height: 1.2em; 382 | max-width: 700px; 383 | margin-left: auto; 384 | margin-right: auto; 385 | padding: 0 20px 20px; 386 | text-align: center; 387 | position: absolute; 388 | left: -999em; 389 | color: #fff; 390 | } 391 | 392 | @media(min-width: 600px) { 393 | .hero h1 { 394 | font-size: 4.5em; 395 | } 396 | } 397 | 398 | .hero p { 399 | text-align: center; 400 | font-size: 1.8em; 401 | line-height: 1.7em; 402 | max-width: 620px; 403 | margin-left: auto; 404 | margin-right: auto; 405 | margin-bottom: 30px; 406 | padding: 0 20px 10px; 407 | color: #fff; 408 | } 409 | 410 | @media(min-width: 600px) { 411 | .hero p { 412 | font-size: 2.2em; 413 | } 414 | } 415 | 416 | .hero-button:link, 417 | .hero-button:visited { 418 | border-radius: 30px; 419 | text-transform: uppercase; 420 | text-decoration: none; 421 | padding: 15px 70px; 422 | font-size: 1.3em; 423 | background-color: #7FDBFF; 424 | color: #00162D; 425 | font-weight: bold; 426 | letter-spacing: 0.04em; 427 | width: 100px; 428 | margin: 0 auto; 429 | display: block; 430 | text-align: center; 431 | } 432 | 433 | .hero-button:hover { 434 | color: #fff; 435 | } 436 | 437 | /********************************************************** 438 | * Benefits 439 | **********************************************************/ 440 | 441 | .benefits { 442 | padding: 50px 20px; 443 | background-color: #f5f5f5; 444 | } 445 | 446 | .benefits h2 { 447 | text-align: center; 448 | font-size: 2.8em; 449 | line-height: 1.2em; 450 | max-width: 700px; 451 | margin-left: auto; 452 | margin-right: auto; 453 | margin-bottom: 50px; 454 | color: #001F3F; 455 | } 456 | 457 | @media(min-width: 600px) { 458 | .benefits h2 { 459 | font-size: 3.5em; 460 | } 461 | } 462 | 463 | .benefit { 464 | border-bottom: 1px dotted #aaa; 465 | max-width: 600px; 466 | margin: 0 auto 40px; 467 | } 468 | 469 | .benefit h3 { 470 | text-align: center; 471 | font-size: 2em; 472 | margin-bottom: 7px; 473 | color: #001F3F; 474 | } 475 | 476 | @media(min-width: 600px) { 477 | .benefits h3 { 478 | font-size: 2.5em; 479 | } 480 | } 481 | 482 | .benefit p { 483 | text-align: center; 484 | font-size: 1.8em; 485 | line-height: 1.4em; 486 | max-width: 700px; 487 | margin-left: auto; 488 | margin-right: auto; 489 | margin-bottom: 30px; 490 | padding: 0 20px 10px; 491 | color: #001F3F; 492 | } 493 | 494 | @media(min-width: 600px) { 495 | .benefit p { 496 | font-size: 2.2em; 497 | } 498 | } 499 | 500 | .benefit-readNowButton:link, 501 | .benefit-readNowButton:visited { 502 | border-radius: 30px; 503 | text-transform: uppercase; 504 | text-decoration: none; 505 | padding: 15px 70px; 506 | font-size: 1.3em; 507 | background-color: #001F3F; 508 | color: #ffffff; 509 | font-weight: bold; 510 | letter-spacing: 0.04em; 511 | width: 100px; 512 | display: block; 513 | text-align: center; 514 | margin: 0 auto; 515 | } 516 | 517 | .benefit-readNowButton:hover { 518 | background-color: #00162D; 519 | color: #7FDBFF; 520 | } 521 | 522 | /********************************************************** 523 | * Chapters 524 | **********************************************************/ 525 | 526 | .chapters { 527 | background-color: #7FDBFF; 528 | padding-top: 40px; 529 | padding-bottom: 40px; 530 | } 531 | 532 | .chapters-inner { 533 | max-width: 700px; 534 | padding: 0 20px; 535 | margin: 0 auto; 536 | } 537 | 538 | .chapters h2 { 539 | font-size: 2.2em; 540 | line-height: 1.2em; 541 | margin-bottom: 10px; 542 | } 543 | 544 | @media(min-width: 600px) { 545 | .chapters h2 { 546 | font-size: 2.5em; 547 | margin-bottom: 15px; 548 | } 549 | } 550 | 551 | .chapters ol { 552 | margin-left: 20px; 553 | font-size: 1.8em; 554 | line-height: 1.7em; 555 | } 556 | 557 | @media(min-width: 600px) { 558 | .chapters ol { 559 | font-size: 2.2em; 560 | } 561 | } 562 | 563 | .chapters-isCurrentPage { 564 | padding-left: 5px; 565 | font-weight: bold; 566 | } 567 | 568 | /********************************************************** 569 | * Got question 570 | **********************************************************/ 571 | 572 | .gotQuestion { 573 | padding-top: 40px; 574 | padding-bottom: 40px; 575 | background-color: #f5f5f5; 576 | } 577 | 578 | .gotQuestion-inner { 579 | max-width: 700px; 580 | padding: 0 20px; 581 | margin: 0 auto; 582 | } 583 | 584 | .gotQuestion h2 { 585 | font-size: 2.2em; 586 | line-height: 1.2em; 587 | margin-bottom: 10px; 588 | } 589 | 590 | @media(min-width: 600px) { 591 | .gotQuestion h2 { 592 | font-size: 2.5em; 593 | margin-bottom: 15px; 594 | } 595 | } 596 | 597 | .gotQuestion p { 598 | font-size: 1.8em; 599 | line-height: 1.7em; 600 | margin-bottom: 30px; 601 | } 602 | 603 | @media(min-width: 600px) { 604 | .gotQuestion p { 605 | font-size: 2.2em; 606 | } 607 | } 608 | 609 | 610 | /********************************************************** 611 | * Share 612 | **********************************************************/ 613 | 614 | .share { 615 | padding-bottom: 60px; 616 | padding-left: 20px; 617 | padding-right: 20px; 618 | max-width: 700px; 619 | margin: 0 auto; 620 | } 621 | 622 | .share-button:link, 623 | .share-button:visited { 624 | border-radius: 30px; 625 | text-transform: uppercase; 626 | text-decoration: none; 627 | padding: 12px 30px; 628 | font-size: 1.1em; 629 | color: #001F3F; 630 | background-color: #eee; 631 | font-weight: bold; 632 | letter-spacing: 0.04em; 633 | width: 150px; 634 | text-align: center; 635 | margin: 0 auto; 636 | } 637 | 638 | .share-button:hover { 639 | background-color: #7FDBFF; 640 | } 641 | 642 | /********************************************************** 643 | * Recs 644 | **********************************************************/ 645 | 646 | .recommendations { 647 | padding: 40px 20px 20px; 648 | } 649 | 650 | .recommendations-title { 651 | text-align: center; 652 | font-size: 2.8em; 653 | line-height: 1.2em; 654 | max-width: 700px; 655 | margin-left: auto; 656 | margin-right: auto; 657 | margin-bottom: 20px; 658 | color: #001F3F; 659 | } 660 | 661 | @media(min-width: 600px) { 662 | .recommendations-title { 663 | font-size: 3.5em; 664 | } 665 | } 666 | 667 | .recommendations-item { 668 | font-style: italic; 669 | margin-left: auto; 670 | margin-right: auto; 671 | padding-top: 30px; 672 | padding-bottom: 30px; 673 | color: #001F3F; 674 | padding-left: 20px; 675 | padding-right: 20px; 676 | border-bottom: 1px dotted #aaa; 677 | max-width: 500px; 678 | } 679 | 680 | @media(min-width: 600px) { 681 | .recommendations-item { 682 | padding-left: 40px; 683 | padding-right: 40px; 684 | } 685 | } 686 | 687 | .recommendations-item:last-child { 688 | border: none; 689 | margin-bottom: 0; 690 | } 691 | 692 | .recommendations-item p { 693 | font-size: 1.8em; 694 | line-height: 1.7em; 695 | margin-left: auto; 696 | margin-right: auto; 697 | max-width: 500px; 698 | color: #001F3F; 699 | text-align: center; 700 | } 701 | 702 | @media(min-width: 600px) { 703 | .recommendations-item p { 704 | font-size: 2.2em; 705 | } 706 | } 707 | 708 | .recommendations-item cite { 709 | font-weight: bold; 710 | } 711 | -------------------------------------------------------------------------------- /assets/img/card1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/assets/img/card1.png -------------------------------------------------------------------------------- /assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/assets/img/logo.png -------------------------------------------------------------------------------- /assets/img/logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/assets/img/logo_small.png -------------------------------------------------------------------------------- /atom.xml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | --- 4 | 5 | 6 | 7 | {{site.name}} 8 | 9 | 10 | {{ site.time | date_to_xmlschema }} 11 | {{site.url}} 12 | 13 | Adam Silver 14 | 15 | 16 | {% for post in site.posts %} 17 | 18 | {{ post.title }} 19 | 20 | {{ post.date | date_to_xmlschema }} 21 | {{site.url}}{{ post.id }} 22 | {{ post.content | xml_escape }} 23 | 24 | {% endfor %} 25 | -------------------------------------------------------------------------------- /browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | #da532c 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Automated deploy script with Circle CI. 4 | 5 | # Exit if any subcommand fails. 6 | set -e 7 | 8 | # Variables 9 | ORIGIN_URL=`git config --get remote.origin.url` 10 | 11 | echo "Started deploying" 12 | 13 | # Checkout gh-pages branch. 14 | if [ `git branch | grep gh-pages` ] 15 | then 16 | git branch -D gh-pages 17 | fi 18 | git checkout -b gh-pages 19 | 20 | # Build site. 21 | # bower install 22 | bundle exec jekyll build 23 | 24 | # Delete and move files. 25 | find . -maxdepth 1 ! -name '_site' ! -name '.git' ! -name '.gitignore' -exec rm -rf {} \; 26 | mv _site/* . 27 | rm -R _site/ 28 | 29 | # Push to gh-pages. 30 | # git config user.name "$USER_NAME" 31 | # git config user.email "$USER_EMAIL" 32 | 33 | git add -fA 34 | git commit --allow-empty -m "$(git log -1 --pretty=%B) [$(date +"%d-%m-%Y")]" 35 | git push -f $ORIGIN_URL gh-pages 36 | 37 | # Move back to previous branch. 38 | git checkout - 39 | 40 | echo "Deployed Successfully!" 41 | 42 | exit 0 -------------------------------------------------------------------------------- /favicon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/favicon-128.png -------------------------------------------------------------------------------- /favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/favicon-16x16.png -------------------------------------------------------------------------------- /favicon-196x196.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/favicon-196x196.png -------------------------------------------------------------------------------- /favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/favicon-32x32.png -------------------------------------------------------------------------------- /favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/favicon-96x96.png -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/favicon.ico -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | id: home 4 | --- 5 | 6 |
7 | 8 | 9 | 10 |

MaintainableCSS

11 |

如何编写 CSS 而不用再去过分担心原有的样式会受你的影响?MaintainableCSS 就是这样一种哲学,教你编写 模块化, 可扩展 以及 可维护 的CSS.

12 | 马上阅读 13 |
14 | 18 | 19 |
20 |

MaintainableCSS 带来的优势

21 |
22 |
23 |

封装以及模块化

24 |

你对样式有完全的控制。

25 |
26 |
27 |

满足任何设计需求

28 |

根据你的需要,这会非常灵活。

29 |
30 |
31 |

无任何工具依赖

32 |

当然你可以使用任何你愿意尝试的工具。

33 |
34 |
35 |

易学性

36 |

读完这篇入门指导,你就知道了。

37 |
38 |
39 |

适合任何规模的项目

40 |

不管你项目规模有多大,MaintainableCSS 都会有用。

41 |
42 |
43 |

在你合适的时间升级

44 |

从今天开始,你就可以选择将其应用到你的项目上。你可以一点一点地升级,而不用一次性地全部搞定。

45 |
46 |
47 |

不会有权重过高的问题

48 |

能够避免因过度覆写而权重过高的问题。每次你都可以认为是在一张空白画板,从零开始写。

49 |
50 |
51 |

状态管理的方便性

52 |

根据状态而改变样式,如 loading, disabledhiding状态等。

53 |
54 |
55 |

不用担心回归测试

56 |

修改一个现有样式的时候,你不会担心会影响其他地方的回归测试。

57 |
58 |
59 |

适合任何规模的团队

60 |

不论团队是只有一人,还是有100人。MaintainableCSS 都非常有用。

61 |
62 |
63 |

语义化的 HTML 和 CSS

64 |

MaintainableCSS 拥抱语义化的 HTML and CSS, 故你可以获得所有的好处。

65 |
66 |
67 |

高性能的 CSS

68 |

基于约定而使用扁平风格和高性能的选择器。

69 |
70 |
71 |

易于发现冗余代码

72 |

非常容易发现冗余代码,找到它,然后删除它。

73 |
74 |
75 |

方便 AB 测试与升级

76 |

想要测试一个模块的不同样式?MaintainableCSS 会让其变得轻松而愉快。

77 |
78 | 马上阅读 79 |
80 |
81 |
82 |

评价

83 |
84 |
85 |

“A handy little read on learning how to write modular and maintainable CSS.” 86 |
Smashing Magazine 87 |

88 |
89 |
90 |
91 |
92 |

“Finally a good book on how to write maintainable CSS.” 93 |
Alexander Dajani 94 |

95 |
96 |
97 |
98 |
99 |

“I actually love everything about this.” 100 |
Simon Taggart 101 |

102 |
103 |
104 |
105 |
106 |

“Totally agree with this approach to CSS.” 107 |
Marcel Reyna 108 |

109 |
110 |
111 |
112 | 113 | {% include chapterList.html %} 114 | 115 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MCSS", 3 | "icons": [ 4 | { 5 | "src": "\/android-chrome-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": 0.75 9 | }, 10 | { 11 | "src": "\/android-chrome-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": 1 15 | }, 16 | { 17 | "src": "\/android-chrome-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": 1.5 21 | }, 22 | { 23 | "src": "\/android-chrome-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": 2 27 | }, 28 | { 29 | "src": "\/android-chrome-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": 3 33 | }, 34 | { 35 | "src": "\/android-chrome-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": 4 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/mstile-144x144.png -------------------------------------------------------------------------------- /mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/mstile-150x150.png -------------------------------------------------------------------------------- /mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/mstile-310x150.png -------------------------------------------------------------------------------- /mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/mstile-310x310.png -------------------------------------------------------------------------------- /mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owenyang0/maintainablecss-cn/aa1350582c4c4f6c564d93f16dee4ead58aba2ea/mstile-70x70.png -------------------------------------------------------------------------------- /safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /sitemap.xml: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | 5 | {% for post in site.posts %} 6 | 7 | {{site.url}}{{ post.url | remove: 'index.html' }} 8 | 9 | {% endfor %} 10 | 11 | {% for page in site.pages %} 12 | {% if page.layout != nil %} 13 | {% if page.layout != 'feed' %} 14 | 15 | {{site.url}}{{ page.url | remove: 'index.html' }} 16 | 17 | {% endif %} 18 | {% endif %} 19 | {% endfor %} 20 | 21 | {% for page in site.chapters %} 22 | {% if page.layout != nil %} 23 | {% if page.layout != 'feed' %} 24 | 25 | {{site.url}}{{ page.url | remove: 'index.html' }} 26 | 27 | {% endif %} 28 | {% endif %} 29 | {% endfor %} 30 | --------------------------------------------------------------------------------