CSS 架构指南

hubuke 8年前
   <p>以命令式风格写 CSS 会很快地导致下面的结果:</p>    <ul>     <li>不够清晰 —— 那些带来了成吨混乱的东西,例如不清晰的依赖(难以删除或者增加东西),</li>     <li>不可维护 —— 当在创建新代码或者改善现有代码的时候效率低下,</li>     <li>重复冗余 —— 使得代码臃肿而且对性能有负面影响,</li>     <li>大量的存在于可扩展性,一致性以及对于新开发者的问题。</li>    </ul>    <p>通常结果就是我们获得了混乱的 UI 和 CSS。不用说都能体会到开发者心中的怒火熊熊!这还将导致乱七八糟的 UX。让我们来看看为了防止上面的情况发生我们能做什么。</p>    <p><strong>优先级</strong></p>    <p>在选择器之间的 <a href="/misc/goto?guid=4959677100691994266">优先级</a> 战争通常反映了糟糕的代码质量。拥有低的优先级将帮助更长时间地维护一个大型 CSS 项目的完整性和性能。</p>    <p>首先避免所有不必要的深层选择器。为了给一个箭头样式,你真的没有必要写出这样的选择器:</p>    <pre>  <code class="language-css">.page-quick-sidebar-wrapper .page-quick-sidebar .page-quick-sidebar-chat .page-quick-sidebar-chat-user .page-quick-sidebar-chat-user-messages .post.out .message .arrow {    }</code></pre>    <p>我们可以使用更有意义的选择器例如 <em>.message-arrow { … }</em> 并且用它来代替 <em>.arrow</em>?或者只需要给 <em>.arrow</em> 写样式如果只有一个箭头需要给样式?</p>    <p>在大多数情况下会出现 <a href="/misc/goto?guid=4959677100784438829">SASS/SCSS 嵌套陷阱</a>。嵌套不应该多于三层。停止趋向于使 SASS 嵌套跟 html 嵌套一致。别尝试使 CSS 选择器视觉上层次分明(这看起来很美丽但导致了维护开销)。为我们的利益着想,<strong>别基于他们在哪里或者他们怎么表现而是基于他们是什么来赋予样式</strong>(位置独立性)。</p>    <p><strong>创建选择器</strong></p>    <p>ID 比类名强了好几个数量级。因此你不能轻易地用类名选择器重载 ID 选择器的样式。避免将 ID 作为样式的钩子,但如果你为了其他东西(例如 JS 钩子)需要也可以使用它们。当创建选择器时似乎类就是最好的解决方案。那标签选择器呢?只有在重置或者应用普遍样式时你才能使用标签。使用 !important 并不是一个安逸的实践,除非「你在使用的时候不会愤怒」。它完美适配你的通用类。</p>    <p><strong>命名</strong></p>    <p>命名约定有益于立刻理解一个特定的样式属于哪一个类别以及它在总体页面里的职责。</p>    <p>这是一些适合应用于任何命名约定里的规则:</p>    <ul>     <li><strong>基于它是什么而不是它看起来或者表现起来怎么样来命名某个事物</strong>.</li>     <li>通常来说,<strong>有更长的类名比更复杂的优先级更好</strong>。</li>    </ul>    <p>在大多数情况下给类和 id 加前缀是不错的。使用前缀和/或命名系统<strong>帮助区分框架和自定义类/id</strong>。更重要的是通过这样做你可以<strong>轻易地避免命名冲突</strong>(例如你希望实现一个日期选择器,它添加了全局类如 .next 或者 .prev。如果你之前已经使用了这些类名,会发生什么?)所以怎么使用前缀?</p>    <ul>     <li><em>.u-hide-text</em> (“u”表示它是一个有特定目的的通用类。它会在很多地方使用而且不应该被扩展。通常你希望确认通用类会赢得优先级战争。 Therefore using !important it’s not bad practice for that case.因此在这个例子中使用 !important 是个不错的选择。)</li>     <li><em>.l-main-nav</em> (“l”指布局或者组件类。用于把模块组合成组件以及将他们定位在页面中)</li>     <li><em>.b-main-nav</em> (“b”前缀能被应用在主块或是模块容器中)</li>     <li><em>.js-header-animate</em> (“js”指这个类只能被 JavaScript 使用。这避免了基于类名的意外破坏行为或测试。)</li>    </ul>    <p><strong>BEM</strong></p>    <p>一种更流行的命名约定是 <a href="/misc/goto?guid=4959677100866528231">BEM</a>。通过使用这种命名约定你会自动地以一组独立的模块“而不是我怎么赋予这个页面样式”来考虑布局。一些常见的 BEM 规则:</p>    <ul>     <li>你希望<strong>只使用类来构建选择器</strong>。在大多数情况下你的选择器是一个独立而有意义的类。</li>     <li>类名从<strong>块/模块</strong>的名字开始,下一个是<strong>元素</strong>的名字(紧接在两个下划线之后),最后是<strong>修饰器</strong>的名字(在两个破折号之后)。例如 <em>.main-nav__item — current</em>。</li>     <li>修饰器既能应用在块上也能应用在元素上。</li>     <li>不能有元素出现在它的块之外。</li>     <li>你可以在它的块内嵌套元素,但是在这种情况下不要写出像这样的选择器: .block__element1__element2。而是始终使用:.block__element1 .block__element2。</li>     <li><strong>块是独立的</strong>,只会共享大部分普遍样式(重置和一些基础样式)。这减少了代码量,以及使其可重用。</li>     <li>你不希望直接在块或者模块上直接应用布局样式。这就是为什么我们想要使用布局类的原因。</li>    </ul>    <p>多亏了 BEM 我们现在有了:</p>    <ul>     <li>模块化 CSS 代码。这使得 CSS 很容易地转换到 React 世界,在这里中你经常希望拥有每一个组件单独的 css 文件;</li>     <li>非常低的优先级;</li>     <li>解耦 HTML 结构和 CSS;</li>     <li>提高可读性(你能够在看 HTML 的时候知道更多关于 CSS 的东西);</li>     <li>不再有命名冲突(单独的模块帮助避免了把 CSS 放在全局范围内);</li>     <li>对于如何在一个块中命名一个新变量的清晰规则;</li>     <li>级联继承样式不再有问题(在你不想要的地方出现意外的样式泄漏);</li>     <li>减少类之后更小的 HTML 以及令 HTML 可重用。</li>    </ul>    <p>相关链接</p>    <p><a href="/misc/goto?guid=4959677100948645883">Łukasz Kliś — To BEM, or not to BEM</a>(波兰语)</p>    <p>移动优先</p>    <p>为什么这个概念是有益的?首先通过实现移动端版本你会强迫去考虑内容层次。你希望以最可行的方法(简单而高效的解决方案)提供最需要的功能和内容。这对于桌面版本来说是有正面作用的。其次,增加比删除要更容易。</p>    <p><strong>编写媒体查询</strong></p>    <p>使用预定义的断点(像 bootstrap 使用的那样)对于栅格管理来说很好但是对于改变模块样式来说不是必要的。添加一些自定义断点完全没有坏处。我们希望我们的 webapp 在宽泛范围内的解决方案中都可以适应地很好。而不只是对于那些使用栅格框架定义的。通常来说使用“min-width”断点是更优雅的方案。尽量避免只使 用“max-width”断点。通过这样做你会得到更少的代码,更少的重载和更少的 !important 声明。</p>    <p>组件,<strong>模块和元素</strong></p>    <p>尽可能快的尝试建立可独立的模块和组件(模块的集合)。当创建类似的模块时记得以适当的 CSS 方式使用 DRY 原理。详见 <a href="/misc/goto?guid=4959677101022833134">这里</a> 和 <a href="/misc/goto?guid=4959677101117845060">这里</a>。</p>    <p><strong>模块,组件和元素之间的区别在哪里?</strong></p>    <p><strong>组件</strong>是模块的集合。在大多数情况下它会跟布局类处在相同的抽象层次。</p>    <p><strong>模块</strong>是元素的集合。应该可重用而不依赖于其他模块。</p>    <p><strong>元素</strong>是不能单独使用和需要父级实体的代码片段。</p>    <p>例:页眉是组件。它包括了模块——导航栏和 logo 模块。 Navigation has items elements.导航栏有项目元素。Logo 有图片和文本元素。</p>    <p>文件和目录结构组织</p>    <p>为了创造可维护的 CSS 架构我们需要比一个巨大的 main.css 文件和第三方目录更多的东西。下面的描述主要基于 <a href="/misc/goto?guid=4959677101196178432">SMACSS</a> 概念。</p>    <p>首先我们将需要一个预处理器用于编译 CSS 文件(在每一次保存之后),生成依赖和教新的 CSS 技巧。出于 debug 需要我们不希望在开发环境中压缩文件。</p>    <p><strong>依赖</strong></p>    <p>我们希望以下面的顺序加载我们的 CSS:</p>    <ol>     <li>第三方样式(框架,插件样式)</li>     <li>下一个是我们的通用部分。我们希望加载所有的变量,mixins 和其他助手(类,占位符)。</li>     <li>如果我们没有使用一个提供了 CSS 重置的框架,那么我们绝对希望引入 normalize.css(或者其他类似的) 加上我们自定义的重置和基础样式。</li>     <li>最后我们可以引入布局和模块样式。</li>    </ol>    <p><strong>项目结构</strong></p>    <p>为了确保布局一致性我们应该努力保持(只保持)全局范围共享 css。</p>    <p><strong>— 第三方</strong> 全局范围使用的工具</p>    <p><strong>— 基础 CSS 重置</strong>(例如 normalize)和 <strong>基础样式</strong>。“基础样式是默认的。他们几乎都是清一色的单元素选择器但也可以包括属性选择器,伪类选择器,后代选择器或者同级选择器。本质上来说,一个基础样式意味着不管这个元素在页面上的何处,它都应该看起来像这样。”</p>    <p><strong>— 依赖</strong> 全局使用的:变量,度量,颜色,排版和表单样式,SASS mixins 和函数,debug 工具。</p>    <p><strong>— 模块</strong> 是可重用的,在我们的设计中模块化的部分。每一个模块总是使用一个文件。</p>    <p><strong>— 布局</strong> 模块的容器。布局将页面划分成多个部分,并使一个或多个模块处在适当的位置,将它们定位在页面中。这是唯一一个你可以添加 margins,width,height 等等的地方。所以布局与模块一起合作,但是模块是独立的单元而且可以在任何上下文里使用。</p>    <p><strong>— 状态</strong> 是用来描述我们的模块或者布局在特定状态下的将会如何显示的方式。是隐藏的还是展开的?是激活的还是未激活的?是关于描述一个模块或者布局在更大或者更小的屏幕里如何显示的。还是关于描述一个模块在不同的视图中例如主页或内页里应该如何显示。</p>    <p> </p>    <p>来自:http://www.zcfy.cc/article/css-architecture-guidelines-1099.html</p>