【Webデザイナ-・コーダー向け】すぐに使えるSCSS入門|Mixinsを作ってみよう編

2012.10.31

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに。

基礎編compass編知らないと損する機能編と今回の「Mixinsを作ってみよう編」で第4回目になります。
全部読んで理解すれば、もうSCSSをがっつり使えるようになっているんじゃないでしょうか!僕もこのシリーズ記事を書きながらドキュメントを読んで色々知ることができました。
今回はプログラムを書いたことのない方にはほんの少し難しいかもしれません・・・でも、投げ出さずに使ってみてください。理解できたときには少しプログラミングが好きになると思います。
それでは、第4回目「Mixinsを作ってみよう編」いってみよー。

SCSS(Sass) Mixinsとは

SCSS(Sass) Mixinsとは簡単に言うとSCSS全体で再使用することができ、多種多様なスタイルを生成できる機能です。
引数を使い生成するスタイルを制御することもできます。

Mixinsの基本

Mixinsを使うには2つのステップが必要です。1に「定義」、2に「読込み(含む)」です。

Mixinsの定義とは(Mixin宣言)

Mixinsの定義には@mixinという宣言を使います。
@mixinの宣言をしたらMixin名を定義し宣言ブロック「{}」を作ります。引数を指定したい場合は宣言ブロックの前に「()」を置きます。

//引数なしのMixin
@mixin dents {
	box-shadow : 0 1px 10px rgba( 0, 0, 0, 0.2 );
}

//引数有りのMixin
@mixin dents ( $shadow_size ) {
	box-shadow : 0 1px $shadow_size rgba( 0, 0, 0, 0.2 );
}

Mixinの読み込み

宣言したMixinは@includeで読み込むことができます。

.box
{
	@include dents;
	@include dents( 15px );
}

引数の指定

引数は複数指定することができます。
また、引数が指定されなかった時用にデフォルト値を設定できます。

//複数の引数指定(カンマ区切り)
@mixin dents ( $shadow_size, $strength_shadow ) {
	box-shadow : 0 1px $shadow_size rgba( 0, 0, 0, $strength_shadow );
}

.box
{
	@include dents( 20px, 0.5 );
}


//デフォルト値を指定してみる
@mixin dents ( $strength_shadow: 10px ) {
	box-shadow : 0 1px $shadow_size rgba( 0, 0, 0, 0.2 );
}

.box
{
	@include dents();
}

Mixinは属性と値だけではなく、宣言ブロックごとスタイルを生成することもできます。もちろん、ネストした宣言ブロックを書くことも可能です。

@mixin dents-box ( $strength_shadow: 10px ) {
	div
	{
		margin : 20px;
		box-shadow : 0 1px $shadow_size rgba( 0, 0, 0, 0.2 );
	}
}

Mixinsに使える便利なコントロール宣言

単純なMixinでも便利ですが、さらに便利にするための4つのコントロール宣言が用意されています。1つ1つの宣言を紹介する前にSCSSで扱えるデータタイプについて知っておきましょう。

SCSSで扱えるデータタイプは6つあります。

  • 数字 - numbers: SCSSの場合10pxなども数字として扱われる
  • 文字列 - strings(クオートで囲う): テキスト
  • 真偽値 - booleans: trueかfalseか
  • カラー - colors: #000000, red, rgba(0, 0, 0, 0.0)
  • - null: 空
  • リスト - lists: カンマで区切られた値(簡易な配列のようなもの)

@if

真偽を判定します。

$content_width: 960px;

//$content_widthが960だと背景が黒くなる
div {
	width: $content_width;
	@if 960 == $content_width {
		background : #000;
	}
}

//960じゃないときの指定をしたい場合@elseを使う
div {
	width: $content_width;
	@if 960 == $content_width {
		background : #000;
	} @else {
		background : #fff;
	}
}

//細かい条件を複数指定したい場合は@elseifを使う
div {
	width: $content_width;
	@if 960 == $content_width {
		background : #000;
	} @elseif 600 > $content_width {
		background : #ccc;
	}
}

@for

シンプルな繰り返し処理を行えます。$i に繰り返されている数が入り、その値をうまく使うことでセレクタをつくることもできます。

@for $i from 1 through 3 {
	.tag-#{$i} { font-size: 1em * (0.1em * $i); }
}
.tag-1 {
	font-size: 1.1em;
}
.tag-2 {
	font-size: 1.2em;
}
.tag-3 {
	font-size: 1.3em;
}

@each

@eachはデータタイプのリストを使い繰り返し処理を行います。カウントではなく任意の文字列を指定できるのでナビゲーションのアイコン指定などに便利ですね。

#nav
{
	@each $nav_item in home, services, products, company, inquiry {
		.nav_#{$nav_item} {
			background-image: url('/images/#{$nav_item}.png');
		}
	}
}
#nav
{
	.nav_home
	{
		background-image: url('/images/home.png');
	}
	.nav_services
	{
		background-image: url('/images/services.png');
	}
	.nav_products
	{
		background-image: url('/images/products.png');
	}
	.nav_company
	{
		background-image: url('/images/company.png');
	}
	.nav_inquiry
	{
		background-image: url('/images/inquiry.png');
	}
}

@while

@whileは条件式がfalseを返すまで繰り返される処理です(良いサンプルが思いつかなかったので公式のドキュメントから引用します)。

$i: 6;
@while $i > 0 {
 	.item-#{$i} { width: 2em * $i; }
 	$i: $i - 2;
}
.item-6 {
	width: 12em;
}
.item-4 {
	width: 8em;
}
.item-2 {
	width: 4em;
}

Mixingをさらに便利にする@content

@contentはMixinを@includeする時に指定できるコンテンツブロックをMixin内に渡すことができる機能です。
前に紹介した「Media Queriesの記述を少し楽にしてくれるSCSS(Sass) Mixin(自作)」でも使われています。

//向きが縦の320pxまでのスクリーンのスタイルを指定するMixin
@mixin mobile {
	@media screen and (max-width : 320px) and (orientation: portrait) {
		@content;
	}
}

.wrapper
{
	width : 960px;
	//モバイルの時にwidthを320pxにする
	@include mobile {
		width : 320px;
	}
}

このmixinを使わない、プレーンなCSSのみでMedia Queriesを記述するには、@media宣言内に規則集合(宣言ブロックとセレクタ)を 書かなければいけません。使い回しもできず毎回@media宣言を書くことになります。

#wrapper
{
    width : 960px;
}
 
@media screen and (max-width: 320px) and (orientation: portrait) {
    #wrapper {
        width : 320px;
    }
}

Mixinとは違う@function宣言

全くそのままですが、関数が使えます。
関数はMixinとは違いCSSのプロパティの値を返すことにも使えます。関数から値を返すには@returnを使います。

例えばJavascriptで仏がいろいろな言葉を叫ぶ関数を作ってみるとこんな感じになります。(余談)

//仏が叫ぶ関数を定義
function hotoke_shout( text ){
	alert( text ); //引数「text」に入った言葉を叫びます。
	console.log('仏が「' + text + '」と叫びました。'); //デベロッパーツールのログに残します。
}

//使ってみる
hotoke_shout( 'ヨシヒコ~ヨシヒコ~~' );

サンプル:勇者を呼んでみるビームを撃つお告げ

本題からそれましたがSCSSで関数を作ってみます。

//ラッパーのサイズ指定
$wrapper_size : 960px;

//ラッパーのサイズを分割しサイズを返す
@function division_width( $division ) {
	@return $wrapper_size / $division;
}

.column
{
	width : division_width( 4 );
}

色を1色指定するだけでCSS3ボタンが作れるMixinを作ってみる

難しくなりますが、上記の紹介内容をうまく使いつつ色を1色指定するだけでCSS3ボタンが作れるMixinを作ってみましょう。

以下にサンプルを載せておきます。このMixinは4つの状態「通常」「ホバー」「アクティブ」「カレント」のスタイルを自動生成します。
このサンプルでは引数にタイプと基準色、文字を白か黒かにする指定をしています。

Mixinのダウンロード

SCSS CSS3 Buttons

SCSS Mixinサンプル

/* *****************************
 *
 * Import file to Scss or Sass.
 *
 **************************** */
@import "compass";


/* ************************************
 *
 * Mobile Device mixin
 * @param $type : button type.
 * @param $color: button base color.
 * @param $font_color: [white|black] button font color.
 *
 *********************************** */
@mixin css3_buttons ( $type: normal, $color: #ccc, $font_color: white ) {
        

        //type
        @if $type == normal {

                //layout
                padding : 5px 10px;

                //typo
                line-height         : 150%;
                text-decoration     : none;
                @if $font_color == white {
                        color       : tint( $color, 90% );
                        @include text-shadow( -1px -1px 0 shade( $color, 25% ) );
                } @else if $font_color == black {
                        color       : shade( $color, 80% );
                        @include text-shadow( 1px 1px 0 tint( $color, 20%) );
                }

                //border
                border      : 1px solid shade( $color, 20% );

                //ornament
                $box_shadow : inset 0 1px 0 tint( $color, 15% ); 
                @include box-shadow( $box_shadow );
                @include border-radius( 5px );
                @include background-image( linear-gradient( $color, shade( $color, 10% ) ) );

                &:hover
                {
                        //typo
                        @if $font_color == white {
                                color       : tint( $color, 90% );
                                @include text-shadow( -1px -1px 0 shade( $color, 30% ) );
                        } @else if $font_color == black {
                                color       : shade( $color, 90% );
                                @include text-shadow( 1px 1px 0 tint( $color, 25%) );
                        }

                        //border
                        border      : 1px solid shade( $color, 40% );

                        //ornament
                        $box_shadow : inset 0 0 10px shade( $color, 30% ), inset 0 1px 0 $color; 
                        @include box-shadow( $box_shadow );
                        @include background-image( linear-gradient( shade( $color, 10% ), shade( $color, 20% ) ) );
                }

                &:active
                {
                        //typo
                        @if $font_color == white {
                                color       : tint( $color, 100% );
                                @include text-shadow( -1px -1px 0 shade( $color, 20% ) );
                        } @else if $font_color == black {
                                color       : shade( $color, 70% );
                                @include text-shadow( 1px 1px 0 tint( $color, 25%) );
                        }

                        //border
                        border      : 1px solid shade( $color, 40% );

                        //ornament
                        $box_shadow : inset 0 0 15px shade( $color, 30% ); 
                        @include box-shadow( $box_shadow );
                        @include background-image( linear-gradient( shade( $color, 20% ), shade( $color, 10% ) ) );

                }

                &.current
                {
                        //typo
                        @if $font_color == white {
                                color       : tint( $color, 90% );
                                @include text-shadow( -1px -1px 0 shade( $color, 40% ) );
                        } @else if $font_color == black {
                                color       : shade( $color, 80% );
                                @include text-shadow( 1px 1px 0 tint( $color, 35%) );
                        }

                        //border
                        border      : 1px solid shade( $color, 40% );

                        //ornament
                        $box_shadow : inset 0 0 10px shade( $color, 40% ), inset 0 1px 0 shade( $color, 15% ); 
                        @include box-shadow( $box_shadow );
                        @include background-image( linear-gradient( shade( $color, 30% ), shade( $color, 20% ) ) );
                }

                &:hover.current
                {
                        //typo
                        @if $font_color == white {
                                color       : tint( $color, 100% );
                                @include text-shadow( -1px -1px 0 shade( $color, 40% ) );
                        } @else if $font_color == black {
                                color       : shade( $color, 70% );
                                @include text-shadow( 1px 1px 0 tint( $color, 35%) );
                        }

                        //border
                        border      : 1px solid shade( $color, 40% );

                        //ornament
                        $box_shadow : inset 0 0 10px shade( $color, 40% ), inset 0 1px 0 shade( $color, 15% ); 
                        @include box-shadow( $box_shadow );
                        @include background-image( linear-gradient( shade( $color, 20% ), shade( $color, 30% ) ) );
                }
        }
}

//使ってみよう
.button
{
        @include css3_buttons( normal, #ccc );
}
.button.blue
{
        @include css3_buttons( normal, #1B9EE0 );
}
.button.red
{
        @include css3_buttons( normal, #FF6969 );
}
.button.white
{
        @include css3_buttons( normal, #fff, black );
}

Output CSS

長いのでこちらをどうぞ

HTML

<p>
	<a href="#" class="button">Button</a>
        <a href="#" class="button white">ボタンだよー</a>
        <a href="#" class="button blue">Button</a>
        <a href="#" class="button blue current">Button</a>
        <a href="#" class="button red">Button</a>
        <a href="#" class="button red current">Button</a>
</p>

サンプル

Button ボタンだよー Button Button Button Button

とても簡単にCSS3ボタンが作れるようになりましたね。

まとめ

いやー、長くなってしまいました。
いかがでしたでしょうか!?プログラミングの経験があまり無い方にとっては少し難しかったかもしれません。この記事で少しでも興味を持ってもらえると書いたかいがあります・・・

この記事でSCSSについての紹介は(とりあえず)最後にしたいと思います!過去の記事をまとめたページ「すぐに使えるSCSS入門シリーズ」がこちらに用意してあるので備忘録としてブックマークしてもらえるとうれしいです。
これからもSCSSを使って効率的な開発をしていきましょう。ではではー。