用 Sass 的占位符和混合宏创建可复用的样式
Sass 的最大好处之一就是具有创建可重用代码块的能力。我经常用 %placeholders 或者 @mixins 创建可重用代码模块。占位符(%placeholders
)和混合宏(@mixins
)之间有很大不同。简而言之:当你需要传递变量时使用混合宏(@mixins
),若不需要,则使用占位符(%placeholder
)。
我目前在做一个网站,该网站在多个页面下使用相同的网格组件:产品,服务及行业都选择相同的结构布局。我不需要任何变量控制样式,所以我首先想到的是使用占位符。使用 Sass3.3 的占位符,你可以通过用 &
引用父级选择器创建 OOCSS/BEM 选择器。在上一个版本,你可以创建嵌套选择器,现在你可以创建新的选择器:
// ---- // Sass (v3.3.6) // Compass (v1.0.0.alpha.18) // ---- /* You can do this with 3.2 & down: */ .parent { text-align: center; .child { text-align: left; } } /* You can do *this* with 3.3: */ .entry { font-size: 1em; &-title { font-size: 2em; } }
/* You can do this with 3.2 & down: */ .parent { text-align: center; } .parent .child { text-align: left; } /* You can do *this* with 3.3: */ .entry { font-size: 1em; } .entry-title { font-size: 2em; }
我想知道是否可以在一个 &-
嵌套顶部用的 %placeholder
,在容器选择器中扩展顶部占位符,让Sass生成所有我需要的新的 &-selectors
。事实证明不会生成选择器名。(如果我选套父/子选择器则它会运行顺畅)看下面我想表达的意思:
// ---- // Sass (v3.3.6) // Compass (v1.0.0.alpha.18) // ---- /* You can generate nested selectors this: */ %parent { text-align: center; .single { text-align: left; } h1 { font-size: 2em; } } .post-archive { @extend %parent; } /* You cannot generate new selectors like this: */ %article { font-size: 1em; &-title { font-size: 2em; } } .post { @extend %article; }
/* You can generate nested selectors this: */ .post-archive { text-align: center; } .post-archive .single { text-align: left; } .post-archive h1 { font-size: 2em; } /* You cannot generate new selectors like this: */ .post { font-size: 1em; }
现在我能使用 @mixin
获取我想要的。那是有效的,但是它会重复代码:每次我运行 @mixin
,在我的样式表中新的地方我都将得到相同的样式。我不想重复。如果用组合选择器,只调用 @mixin
一次,那么我能避免重复:
// ---- // Sass (v3.3.6) // Compass (v1.0.0.alpha.18) // ---- /* Here's my mixin, but it will repeat itself too much for my taste: */ @mixin grid() { width: 100%; &-item{ width: 33%; padding: 1em; } } .products { @include grid(); } .services { @include grid(); } /* Ah, here's a better way to use the mixin. Only problem is I have to use put all my parent classes in the same place. */ .products, .services { @include grid(); }
/* Here's my mixin, but it will repeat itself too much for my taste: */ .products { width: 100%; } .products-item { width: 33%; padding: 1em; } .services { width: 100%; } .services-item { width: 33%; padding: 1em; } /* Ah, here's a better way to use the mixin. Only problem is I have to use put all my parent classes in the same place. */ .products, .services { width: 100%; } .products-item, .services-item { width: 33%; padding: 1em; }
这几乎是我知道的最枯燥无味的解决方式了。如果你不需要保持父选择器为独立部分,你可以同时一起申明他们并且在他们上面同时运行@mixin
。但是,如果你喜欢先进的Sass且不介意付出额外的劳动,则请继续阅读下面的内容。
如果你需要保持你的父级/容器选择器为独立部分,却仍然想避免相同的样式,你可以在项目中先设置空列表变量,在适合的地方为每个单独的部分中增加父级类,然后在空列表尾部调用 @mixin
。下面例子可以说明我的意思:
// ---- // Sass (v3.3.6) // Compass (v1.0.0.alpha.18) // ---- $red: #ff4242; // Declare this variable early $parent-classes: ''; // This mixin holds the style code you want to repeat @mixin grid() { width: 100%; &-item { width: 33%; padding: 1em; &-title { color: $red; text-transform: uppercase; } } } // In _products.scss: $parent-classes: join('.products-grid', $parent-classes); // In _services.scss: $parent-classes: join('.services-grid', $parent-classes); // In _industries.scss: $parent-classes: join('.industries-grid', $parent-classes); // Do this near the end: @if $parent-classes != '' { $i: 1; $return: ''; @each $class in $parent-classes { @if $i > 1 { $return: $return + ", "; } $return: $return + $class; $i: $i + 1; } #{$return} { @include grid(); } } /* Read the detailed explanation behind this gist here: http://jamessteinbach.com/css/sass/creating-repeatable-style-pattern-sass-placeholders-vs-mixins/ */
.industries-grid, .services-grid, .products-grid { width: 100%; } .industries-grid-item, .services-grid-item, .products-grid-item { width: 33%; padding: 1em; } .industries-grid-item-title, .services-grid-item-title, .products-grid-item-title { color: #ff4242; text-transform: uppercase; } /* Read the detailed explanation behind this gist here: http://jamessteinbach.com/css/sass/creating-repeatable-style-pattern-sass-placeholders-vs-mixins/ */
最后的 @if
循环:
- 确保
$parent-classes
不是空的 - 把所有想转化为以逗号分隔的字符串
- 字符串包含的类中调用
@mixin
。
现在没有 @mixin
代码是重复的,所有的父类可以存在他们自己的部分中,所有的 OOCSS/BEM 子项类能够正确生成。
当然,这个不只是适用于网格系统,它适用于任何嵌套样式,这些样式你需要在元素重复用不同类名称。请在评论中让我知道你如何使用这种模式。或者,如果你找到一个更好的方式,也分享一下,谢谢!
更新
感谢 Hugo,他提交了一个 更为简洁的版本,该版本用一种更直接的方式处理父组合选择器,从而不需要使用最后的 @if
循环:
// ---- // Sass (v3.3.8) // Compass (v1.0.0.alpha.19) // ---- $red: #ff4242; // Declare this variable early $parent-classes: (); // This mixin holds the style code you want to repeat @mixin grid() { width: 100%; &-item { width: 33%; padding: 1em; &-title { color: $red; text-transform: uppercase; } } } // In _products.scss: $parent-classes: append($parent-classes, #{'.products-grid'}, comma); // In _services.scss: $parent-classes: append($parent-classes, #{'.services-grid'}, comma); // In _industries.scss: $parent-classes: append($parent-classes, #{'.industries-grid'}, comma); // Do this near the end: #{$parent-classes} { @include grid(); } /* Read the detailed explanation behind this gist here: http://jamessteinbach.com/css/sass/creating-repeatable-style-pattern-sass-placeholders-vs-mixins/ */
.products-grid, .services-grid, .industries-grid { width: 100%; } .products-grid-item, .services-grid-item, .industries-grid-item { width: 33%; padding: 1em; } .products-grid-item-title, .services-grid-item-title, .industries-grid-item-title { color: #ff4242; text-transform: uppercase; } /* Read the detailed explanation behind this gist here: http://jamessteinbach.com/css/sass/creating-repeatable-style-pattern-sass-placeholders-vs-mixins/ */
英文出处:http://jamessteinbach.com/css/sass/creating-repeatable-style-pattern-sass-placeholders-vs-mixins
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论