第5章 現場で使える実践Sassテクニック
5-2 レイアウト・パーツで使えるテクニック
clearfix をミックスインで活用する
@mixin clearfix { &::after { content: ""; display: block; clear: both; } }
@mixin clearfix { &::after { content: ""; display: block; clear: both; } }
.item { background: #eee; } .item::after { content: ""; display: block; clear: both; } .item .image { float: left; width: 100px; } .item .text { float: left; }
変数を使って、サイドバーの幅を自動的に計算する
// 全体の幅 $wrap-width: 960px; // メインエリアの幅 $main-width: 640px; // サイドバーの幅 $side_width: $wrap_width - $main_width - 20; #contents { width: $wrap_width; } #main { width: $main_width; } #side { width: $side_width; }
#contents { width: 960px; } #main { width: 640px; } #side { width: 300px; }
#side { width: 294px; }
nullで簡単に条件分岐をしてレイアウトをする
$height: false; .item { width: 500px; @if $height { height: $height; } }
.item { width: 500px; }
// 高さが必要な場合は値を単位付きで。不要な場合はnull。 $height: null; .item { width: 500px; height: $height; }
.item { width: 500px; }
@mixin itemBox ($width, $height, $margin:null, $padding:null) { width: $width; height: $height; margin: $margin; padding: $padding; } .itemA { // 不要なプロパティはnull。 @include itemBox(100px, null, 10px, 20px); } .itemB { @include itemBox(null, auto, 20px auto); }
.itemA { width: 100px; margin: 10px; padding: 20px; } .itemB { height: auto; margin: 20px auto; }
$duration: null; a { transition: all $duration linear; }
a { transition: all linear; }
calcとSassを組み合わせて四則演算を便利に使う
.item { width: calc(100% - 1px * 2); }
.item { width: calc(100% - 1px * 2); }
$border: 1px; .item { width: calc(100% - $border * 2); }
.item { width: calc(100% - $border * 2); }
$border: 1px; .item { width: calc(100% - #{$border} * 2); }
.item { width: calc(100% - 1px * 2); }
$border: 100px - 1px * 2; .item { width: calc(#{$border}); }
.item { width: calc(98px); }
$border: "100px - 1px * 2"; .item { width: calc(#{$border}); }
.item { width: calc(100px - 1px * 2); }
$box: "100px - 1px * 2"; $contents: "100% - 20px"; .item { width: calc(#{$contents} - #{$box}); }
.item { width: calc(100% - 20px - 100px - 1px * 2); }
@for を使って余白調整用のclassを生成する
$spaceClass: true !default; $spacePadding: false !default; $endValue: 10 !default; @if $spaceClass { @for $i from 0 through $space_endValue { .mt#{$i * 5} { margin-top: 5px * $i !important; } .mb#{$i * 5} { margin-bottom: 5px * $i !important; } @if $spacePadding { .pt#{$i * 5} { padding-top: 5px * $i !important; } .pb#{$i * 5} { padding-bottom: 5px * $i !important; } } } }
.mt0 { margin-top: 0px !important; } .mb0 { margin-bottom: 0px !important; } .mt5 { margin-top: 5px !important; } .mb5 { margin-bottom: 5px !important; } ...(略)... .mt50 { margin-top: 50px !important; } .mb50 { margin-bottom: 50px !important; }
リストマーカー用の連番を使ったclass名を作成する
%markBase { padding-left: 15px; background-position: 0em .5em; background-repeat: no-repeat; } @for $i from 1 through 3 { .mark_#{$i} { @extend %markBase; background-image: url(../img/mark_#{$i}.png); } }
.mark_1, .mark_2, .mark_3 { padding-left: 15px; background-position: 0em .5em; background-repeat: no-repeat; } .mark_1 { background-image: url(../img/mark_1.png); } .mark_2 { background-image: url(../img/mark_2.png); } .mark_3 { background-image: url(../img/mark_3.png); }
連番を使ったclass名のゼロパディング(0埋め)をする
$tmp: ""; @for $i from 1 through 15 { @if $i < 10 { $tmp: "0#{$i}"; } @else { $tmp: $i; } .mark_#{$tmp} { background-image: url(../img/mark_#{$tmp}.png); } }
.mark_01 { background-image: url(../img/mark_01.png); } .mark_02 { background-image: url(../img/mark_02.png); } ...(略)... .mark_14 { background-image: url(../img/mark_14.png); } .mark_15 { background-image: url(../img/mark_15.png); }
文字リンクカラーのミックスインを作る
@mixin link-color($normal, $hover) { color: $normal; &:hover { color: $hover; text-decoration: none; } } a { @include link-color(#f00, #00f); }
a { color: red; } a:hover { color: blue; text-decoration: none; }
$normal: #f00; $hover: #00f; @mixin link-color($n:$normal, $h:$hover) { color: $n; &:hover { color: $h; text-decoration: none; } } a { @include link-color; }
a { color: red; } a:hover { color: blue; text-decoration: none; }
@mixin link-color2($n) { color: $n; &:hover { color: lighten($n, 30%); text-decoration: none; } } a { @include link-color2(#f00); }
a { color: red; } a:hover { color: #ff9999; text-decoration: none; }
複数の値を@eachでループし、ページによって背景を変更する
$setBG: top, about, company, contact; @each $i in $setBG { .body-#{$i} { background-image: url(../img/bg_#{$i}.png); } }
.body-top { background-image: url(../img/bg_top.png); } .body-about { background-image: url(../img/bg_about.png); } .body-company { background-image: url(../img/bg_company.png); } .body-contact { background-image: url(../img/bg_contact.png); }
$setBG: top red, about blue, company green, contact yellow;
@each $i in $setBG { .body-#{nth($i, 1)} { background-image: url(../img/bg_#{nth($i, 2)}.png); } }
.body-top { background-image: url(../img/bg_red.png); } .body-about { background-image: url(../img/bg_blue.png); } .body-company { background-image: url(../img/bg_green.png); } .body-contact { background-image: url(../img/bg_yellow.png); }
$setBG: (top red)(about blue)(company green)(contact yellow); $setBG: (top,red)(about,blue)(company,green)(contact,yellow); $setBG: ((top)(red))((about)(blue))((company)(green))((contact)(yellow));
シンプルなグラデーションのミックスインを作る
@mixin linear-gradient($color: #f00, $way:to bottom, $percent: 20%) { background-image: linear-gradient($way,$color 0%, lighten($color, $percent) 100%); }
.item { @include linear-gradient; }
.item { background-image: linear-gradient(to bottom, #f00 0%, #ff6666 100%); }
.item { @include linear-gradient(#999, left, 50%); }
.item { background-image: linear-gradient(to bottom, #f00 0%, #ff6666 100%); }
Map型と@eachを使ってSNSアイコンを管理する
// Map型を使って定義 $sns-colors: ( twitter: #1b95e0, facebook: #3b5998, googleplus: #dc4e41, ); // SNSアイコン .sns { &__btn { background-repeat: no-repeat; // @each で処理を繰り返す @each $key, $value in $sns-colors { &.-#{$key} { background-image: url(/img/icon_#{$name}.png); background-color: $value; } } } }
.sns__btn { background-repeat: no-repeat; } .sns__btn.-twitter { background-image: url(/img/icon_twitter.png); background-color: #1b95e0; } .sns__btn.-facebook { background-image: url(/img/icon_facebook.png); background-color: #3b5998; } .sns__btn.-googleplus { background-image: url(/img/icon_googleplus.png); background-color: #dc4e41; }
// Mapを使ってファイル名と背景色を定義 $sns-colors: ( twitter: '01.png' '#1b95e0', facebook: '02.jpg' '#3b5998', googleplus: 'gplus.png' '#dc4e41', );
// SNSアイコン .sns { &__btn { background-repeat: no-repeat; // @each で処理を繰り返す @each $key, $values in $sns-colors { &.-#{$key} { background-image: url(/img/icon/#{nth($values, 1)}); background-color: #{nth($value, 2)}; } } } }
.sns__btn { background-repeat: no-repeat; } .sns__btn.-twitter { background-image: url(/img/icon/01.png); background-color: #1b95e0; } .sns__btn.-facebook { background-image: url(/img/icon/02.jpg); background-color: #3b5998; } .sns__btn.-googleplus { background-image: url(/img/icon/gplus.png); background-color: #dc4e41; }
// SNS設定 $sns-config:( colors: ( twitter: #1b95e0, facebook: #3b5998, googleplus: #dc4e41, ), sizes: ( sm: 25%, md: 50%, lg: 100%, ) );
// SNSアイコン .sns { &__btn { @each $name, $color in map-get($sns-config, 'colors') { &.-#{$name} { background: $color url(/img/icon_#{$name}.png) no-repeat center; } } @each $size, $width in map-get($sns-config, 'sizes') { &.-#{$size} { width: $width; } } } }
.sns__btn.-twitter { background: #1b95e0 url(/img/icon_twitter.png) no-repeat center; } .sns__btn.-facebook { background: #3b5998 url(/img/icon_facebook.png) no-repeat center; } .sns__btn.-googleplus { background: #dc4e41 url(/img/icon_googleplus.png) no-repeat center; } .sns__btn.-sm { width: 25%; } .sns__btn.-md { width: 50%; } .sns__btn.-lg { width: 100%; }
値が比較しづらいz-indexをMap型で一括管理する
$layer: ( modal : 100, header : 20, tooltip : 10, default : 1 );
@mixin z-index($key) { z-index: map-get($layer, $key); } .modal { @include z-index(modal); } .header { @include z-index(header); } .tooltip { @include z-index(tooltip); }
.modal { z-index: 100; } .header { z-index: 20; } .tooltip { z-index: 10; }
@functionを使ってpx指定する感覚でフォントサイズをrem指定する
$baseFontSize: 16; html { font-size: $baseFontSize + px; } @function rem($pixels, $context: $baseFontSize) { @return $pixels / $context * 1rem; }
.text { font-size: rem(12); }
.text { font-size: 0.875rem; }
.text { font-size: rem(14, 12); }
.text { font-size: 1.16667rem; }
ネストしたセレクタをselector-replace()を使って書き換える
.block { .item-A { a { background: red; @at-root #{selector-replace(&,".item-A", ".item-B")} { background: blue; } } } }
.block .item-A a { background: red; } .block .item-B a { background: blue; }
@mixin replace($original, $replacement) { @at-root { #{selector-replace(&, $original, $replacement)} { @content } } }
.block { .item { a { width: 85%; @include replace(".block", ".block .inner") { width: 100%; } } } }
.block .item a { width: 85%; } .block .inner .item a { width: 100%; }
#main { .block { .link { padding-left: 20px; @include replace(".link", "a.link") { display: inline-block; padding-left: 15px; } } } }
#main .block .link { padding-left: 20px; } #main .block a.link { display: inline-block; padding-left: 15px; }
selector-extend() を使い、親セレクタだけ変更して同一スタイルを適用させる
.block { .item-A { padding: 10px; ul { width: 500px; li { margin-bottom: 10px; a { background: blue; } } } } .item-B { padding: 20px; ul { li { a { background: blue; } } } } }
.block { .item-A { padding: 10px; ul { width: 500px; li { margin-bottom: 10px; a { @at-root #{selector-extend(&, ".item-A", ".item-B")} { background: blue; } } } } } .item-B { padding: 20px; } }
.block .item-A { padding: 10px; } .block .item-A ul { width: 500px; } .block .item-A ul li { margin-bottom: 10px; } .block .item-A ul li a { background: blue; } .block .item-B { padding: 20px; } .block .item-B ul li a { background: blue; }
.block .item-A { padding: 10px; } .block .item-A ul { width: 500px; } .block .item-A ul li { margin-bottom: 10px; } .block .item-A ul li a, .block .item-B ul li a { background: blue; } .block .item-B { padding: 20px; }