前端架构 --- css模块化

字数 4076 阅读 701 喜欢 4

前端架构是一系列工具和流程的集合,旨在提升前端代码的质量,并实现高效、可持续的工作流。今天主要分享的是其中的前端中CSS如何进行模块化开发。

过去处理HTML的方法

过去,HTML通常被分为两大阵营:程序式和静态式。

程序式HTML:自动化程度100%,可控制程度接近为0

这通常适合由于前端团队参与项目之前,项目的功能开发(包括HTML输出)已经进行了几周甚至几个月了(例如使用jsp,页面也是后端进行输出的)。如果标记源码被复杂的渲染过程打乱,而且还来自不同的模版,那么情况就会变的更加糟糕。

这意味着,对于任何不是后端复杂性的人而言,更新HTML会变得异常困难。而往往到了这个适合,后端开发者已经开始着手别的任务了,没有事件回过头来进行任何重大的修改。

这种制约因素的影响是,为了把内容更好的嵌入HTML中,编辑人员和后端开发者宁可写一堆标记和CSS类名。最终,他们编写的代码可能会是这样:

<div id="header" class="clearfix">
    <div id="header-screen" class="clearfix">
        <div id="header-inner" class="container-122 clearfix">
            <div id="nav-header" role="navigation">
                <div class="region region-navigation">
                    <div class="block block-system block-menu">
                        <div class="block-inner">
                            <ul class="menu">
                                <li class="first leaf">
                                    <a href="/start">Get Started</a>

这段代码显示了一个简单的页面顶部,即使在填充内容之前都可以包含10层嵌套,更可怕的是,在实际开发中这还是特别夸张的现象,经验告诉我们,他还能嵌套更多。

以前,这种“div乱炖”或许确实有助于我们把静态ps图像做成HTML页面,但是随着我们的需求日渐成熟,我们急需更好的方法来驾驭它们。

静态标记:自动化程度接近于0,可控程度100%

如果我们的项目规模比较小,或者任务只是开发的一个需要填充一大块主题区域的页面,那么编写静态HTMl会更为方便一点。虽然这种情况灵活性很大,但是也意味着我们必须负责维护所有的代码,当需求变更是我们需要每个页面单独手动修改,所以我们的代码会是这样的:

<header>
    <section>
        <nav>
            <div>
                <ul>
                    <li>
                        <a href="products">Products</a>
                        <ul>
                            <li>
                                <a href="/socjs">Socks</a>

为了保持简洁,语义化是首选,应用样式所以来的是HTML5元素名称和他们的层级关系,而非CSS类名。我们的HTML中没有css类名,主导航的样式会自动继承到二级导航的锚地按上面,最终我们往往会添加后代选择起:

header > section > nav > div > ul > li > a {
    color: white;
}
header > section > nav > div > ul > li > ul > li > a{
    color: blue;
}

过去,这种静态标记的方式使得对于任何一个悬停状态或者激活状态选择器,代码至少得写那么长。你根本不想看三级导航会被写成什么样子,更不要想四级甚至五级导航了...

平衡可控性和自动化

我们都在追求的理想状态是,网站上的每一行HTML都是有程序自动生成,而作为前端开发人员,我们只需要管理好这个用来产生HTML的模版和流程。遗憾的是显示并非如此,即使实在最好的情况下,也需要用户去生成内容,而这些内容是无法自动添加css类名的。我们只能通过模版来决定类似表格,表单和导航栏这样的HTML,这样也算是给我门带来了一定的灵活性和必要的自动化。

模版化和静态化的区别在于,程序执行完成之后,我们还可以通过一套类名系统给html添加css类名,并且不在通过元素标签和层级关系来决定视觉外观。

<nav class="nav">
    <ul class="nav__container">
        <li class="nav__item">
            <a class="nav__link" href="/products">
                <ul class="nav__container--secondary">
                    <li class="nav__item--secondary">
                        <a class="nav__link--secondary" href="/socks">

上面的这种方案似乎相当冗长,其实这一定没有什么好辩解的,但是我们给每个元素都添加了对应的css类名,这样看起来更加清晰一点,更加模块化一点,而且具有复用性。我们可以作为通用模版去使用。

CSS模块化

要使用这种模块化方法去定义html,我们需要先改变构建页面的方法和思路。单独的静态网页其实压根就不存在,所谓的网页都已经成为了过去。

如今,css理论几乎和css或者js框架一样繁多,但是css或js框架的用法比较繁琐,而且必须成套使用,而css理论更多是阐述html和css之间的关系,而不是预编译的代码库,因此使用起来会更为灵活。

当然,没有那个方法论是完美的,你可能会发现,一个项目与某个方法比较契合,但是另一个项目可能更适合另外一种方法。所以你完全可以创造一套自己的方法论,或者将现有的理论根据自己的需求进行一些修改,因此当你犹豫不决,不知道该使用那个方法论的时候,不如先看看一些比较接触的方法论,然后再根据自己手里的项目进行分析。

OOCSS方法

  • 分离结构和外观

    将视觉特性定义为可复用的单元,比如simpleclass就代表使用直角,complex则表示使用圆角甚至还加了阴影。

  • 分离容器和内容

    不再将元素位置作为样式的限定词。和在容器内标记的CSS类名不同,我们现在使用的是可复用的CSS类名,比如toggle-title,他应用于相应的文本处理上,但是不管这个文本的元素是什么。这种方式下如果没有应用别的CSS类名,你可以让标签以默认的样式呈现。

SMACSS方法

Scalable and Modular Architecyure for CSS,模块化架构的可扩展CSS方法。

  • 基础

    如果不添加css类名,标记会以什么外观呈现。

  • 布局

    把页面分成一些区域。

  • 模块

    设计中的模块化、可复用的单元。

  • 状态

    描述在特定的状态或者情况下,模块或布局的显示方式。

  • 主题

    一个可选的视觉外观层,可以让你更换不同的主题。

BEM方法

Block Element Modifier,块元素修饰符

BEM使我们要看到第三个方法,是SMACSS的另外一个方面。BEM只是CSS类名命名规则。它并不涉及如何书写你的CSS的结构,而只是建议每个元素都添加带有如下内容的CSS类名。

  • 块名

    所属组建的名称。

  • 元素

    元素再块里面的名称。

  • 修饰符
    任何与块或者元素相关联的修饰符。

BEN使用非常简洁的约定来创建CSS类名,而这些字符串可能会相当长。元素名加在双下滑线后(例如toggle__details),修饰符加在双横杠后面(如toggle__details——active)。这里的details是元素,active是修饰符,这个约定使得CSS类名便得非常清晰。使用双横纲是为了避免呢块名被混淆成修饰符。
这个方法在OOCSS或者SMACSS里使用的好处时候,每个CSS类名都能详细地描述了它实现了什么。在代码中没有open或者is-active这样只在特定背景下才能理解的CSS类名。如果单独看open和is-active这连个名字,我们并不知道他们的含义是什么。虽然BEM方法看起来很累赘、很冗余,但是当看到toggle__details--active的CSS类名,我们就知道它是表示:这个元素的名称是details,位置在toggle组件里,状态为激活状态。

选择适合的方案

当然,我们项目中最重要的还是要找到一个适合的解决方案。不要因为一套规范很流行或者别的团队正在使用就选择它。着三个方法都提供了类似的工具,并且以相近的方式在系统中使用。