公開日: 2019-08-21
更新日: 2020-05-27

Laravel Mixを使って、CSSフレームワークをカスタマイズする

Laravel Mix

spectre.cssはコード量がとても少ないのに、たくさんのコンポーネントをサポートしている、とても優秀なCSSフレームワークです。 でも、実際に使っていると、flexboxのjustify-contentのクラスがなかったりして、物足りなさを感じました。 そこで、Tachyonsというフレームワークからflexboxの定義を追加することにしました。

TachyonsはUtilityファーストで、非常に直行性が高いCSSフレームワークです。 プロパティとプロパティ値の組み合わせに、推測可能なクラス名が割り当てられます。 例えば、flexboxのjustify-content: space-around;を使う場合には、クラスにjustify-aroundを指定することで実現できます。

SCSSのファイルもきれいに分割されていて、メンテナンスが高く、簡単にspectre.cssにTachyonsのflexboxの定義を追加することができました。 そこで、その設定を紹介します。

まず、webpack.mix.jsです。サイト共通のcssとしてapp.cssを、のみログのcssとしてnomilog.cssをそれぞれpublic/css以下に出力します。

mix.sass('resources/sass/app.scss', 'public/css')
   .sass('resources/sass/nomilog.scss', 'public/css')
   .scripts(['node_modules/zxcvbn/dist/zxcvbn.js'], 'public/js/zxcvbn.js')
   .scripts(['resources/js/password_validation.js'], 'public/js/password_validation.js');
            

次にサイト共通のcssを出力するapp.scssです。 本来は、node_modules以下にあるspectre.scssを読み込むのですが、ファイルを修正するので、ローカルにコピーしています。

@import  'variables';

@import  'common';

// Tachyons' Flexbox
@import  'node_modules/tachyons-sass/scss/_flexbox';

// Spectre
// @import  "node_modules/spectre.css/src/spectre";
@import  "spectre";

            

app.scssで最初に読み込んでいる_variables.scssには、色などのカスタマイズを設定しています。 z-indexはどれがどの値なのかひと目でわかるように変数にしています。 また、Tachyonsの_flexbox.scssをコンパイルするのに必要な$breakpointも、ここで定義しています。

$primary-color: #0277bd;
$primary-color-dark:  darken($primary-color, 3%);
$primary-color-light: lighten($primary-color, 3%);
$light-color: #fff;

$top-menu-z-index:    2;
$bottom-menu-z-index: 2;

// Used in spectre and flexbox by tachyons
$breakpoint-not-small: '(min-width: 559px)' !default;
$breakpoint-medium: '(min-width: 560px) and (max-width: 959px)' !default;
$breakpoint-large: '(min-width: 960px)' !default;
            

_commons.scssは、独自に追加したクラスを定義します。

.d-table {
  display: table;
}

.d-table-cell {
  display: table-cell;
}

.nowrap {
  white-space: nowrap;
}

.overflow-x-scroll {
  overflow-x: scroll;
}

.overflow-y-scroll {
  overflow-y: scroll;
}
            

Tachyonsの_flexbox.scssを読み込みます。

// Converted Variables


// Custom Media Query Variables


/*

  FLEXBOX

  Media Query Extensions:
    -ns = not-small
    -m  = medium
    -l  = large

*/

.flex { display: flex; }
.inline-flex { display: inline-flex; }
            

spectre.scssを読み込みます。_layout.scssの中身を修正したいので、_layout.scss以外はオリジナルのscssを読み込むように修正します。 まず、以下がオリジナルのspectre.scssです。

// Variables and mixins
@import  "variables";
@import  "mixins";

/*! Spectre.css v#{$version} | MIT License | github.com/picturepan2/spectre */
// Reset and dependencies
@import  "normalize";
@import  "base";

// Elements
@import  "typography";
@import  "asian";
@import  "tables";
@import  "buttons";
@import  "forms";
@import  "labels";
@import  "codes";
@import  "media";

// Layout
@import  "layout";
@import  "hero";
@import  "navbar";

// Components
@import  "accordions";
@import  "avatars";
@import  "badges";
@import  "breadcrumbs";
@import  "bars";
@import  "cards";
@import  "chips";
@import  "dropdowns";
@import  "empty";
@import  "menus";
@import  "modals";
@import  "navs";
@import  "pagination";
@import  "panels";
@import  "popovers";
@import  "steps";
@import  "tabs";
@import  "tiles";
@import  "toasts";
@import  "tooltips";

// Utility classes
@import  "animations";
@import  "utilities";
            

次に修正後のspectre.sccsです。 _layout.sccsについては、ローカルのものを読み込み、それ以外については、オリジナルのファイルを読み込むように設定しています。

// Variables and mixins
@import  "node_modules/spectre.css/src/variables";
@import  "node_modules/spectre.css/src/mixins";

/*! Spectre.css v#{$version} | MIT License | github.com/picturepan2/spectre */
// Reset and dependencies
@import  "node_modules/spectre.css/src/normalize";
@import  "node_modules/spectre.css/src/base";

// Elements
@import  "node_modules/spectre.css/src/typography";
@import  "node_modules/spectre.css/src/asian";
@import  "node_modules/spectre.css/src/tables";
@import  "node_modules/spectre.css/src/buttons";
@import  "node_modules/spectre.css/src/forms";
@import  "node_modules/spectre.css/src/labels";
@import  "node_modules/spectre.css/src/codes";
@import  "node_modules/spectre.css/src/media";

// Layout
@import  "layout";
@import  "node_modules/spectre.css/src/hero";
@import  "node_modules/spectre.css/src/navbar";

// Components
@import  "node_modules/spectre.css/src/accordions";
@import  "node_modules/spectre.css/src/avatars";
@import  "node_modules/spectre.css/src/badges";
@import  "node_modules/spectre.css/src/breadcrumbs";
@import  "node_modules/spectre.css/src/bars";
@import  "node_modules/spectre.css/src/cards";
@import  "node_modules/spectre.css/src/chips";
@import  "node_modules/spectre.css/src/dropdowns";
@import  "node_modules/spectre.css/src/empty";
@import  "node_modules/spectre.css/src/menus";
@import  "node_modules/spectre.css/src/modals";
@import  "node_modules/spectre.css/src/navs";
@import  "node_modules/spectre.css/src/pagination";
@import  "node_modules/spectre.css/src/panels";
@import  "node_modules/spectre.css/src/popovers";
@import  "node_modules/spectre.css/src/steps";
@import  "node_modules/spectre.css/src/tabs";
@import  "node_modules/spectre.css/src/tiles";
@import  "node_modules/spectre.css/src/toasts";
@import  "node_modules/spectre.css/src/tooltips";

// Utility classes
@import  "node_modules/spectre.css/src/animations";
@import  "node_modules/spectre.css/src/utilities";
            

Tachyonsでは、_variables.scssに3つのブレイクポイントが設定されています。

$breakpoint-not-small: '(min-width: 30em)' !default;
$breakpoint-medium: '(min-width: 30em) and (max-width: 60em)' !default;
$breakpoint-large: '(min-width: 60em)' !default;
            

一方、spectre.cssでは、_variables.scssに6つのブレイクポイントが設定されています。

$size-xs: 480px !default;
$size-sm: 600px !default;
$size-md: 840px !default;
$size-lg: 960px !default;
$size-xl: 1280px !default;
$size-2x: 1440px !default;
            

こんなにたくさんのブレイクポイントは必要ないので、spectre.cssのブレイクポイントをTachyons側に合わせて減らします。 すでに_variables.scssに設定済みです。最終的に、以下のように_layout.scssを修正しました。

// Layout
.container {
  margin-left: auto;
  margin-right: auto;
  padding-left: $layout-spacing;
  padding-right: $layout-spacing;
  width: 100%;

  $grid-spacing: ($layout-spacing / ($layout-spacing * 0 + 1)) * $html-font-size;

  // &.grid-ns {
  //   max-width: $grid-spacing * 2 + $size-ns;
  // }

  &.grid-m {
    max-width: $grid-spacing * 2 + $size-m;
  }

  &.grid-l {
    max-width: $grid-spacing * 2 + $size-l;
  }
}

// Responsive breakpoint system
.show-ns,
.show-m,
.show-l {
  display: none !important;
}

// Responsive grid system
.columns {
  display: flex;
  flex-wrap: wrap;
  margin-left: -$layout-spacing;
  margin-right: -$layout-spacing;

  &.col-gapless {
    margin-left: 0;
    margin-right: 0;

    & > .column {
      padding-left: 0;
      padding-right: 0;
    }
  }
  &.col-oneline {
    flex-wrap: nowrap;
    overflow-x: auto;
  }
}
.column {
  flex: 1;
  max-width: 100%;
  padding-left: $layout-spacing;
  padding-right: $layout-spacing;

  &.col-12,
  &.col-11,
  &.col-10,
  &.col-9,
  &.col-8,
  &.col-7,
  &.col-6,
  &.col-5,
  &.col-4,
  &.col-3,
  &.col-2,
  &.col-1,
  &.col-auto {
    flex: none;
  }
}
.col-12 {
  width: 100%;
}
.col-11 {
  width: 91.66666667%;
}
.col-10 {
  width: 83.33333333%;
}
.col-9 {
  width: 75%;
}
.col-8 {
  width: 66.66666667%;
}
.col-7 {
  width: 58.33333333%;
}
.col-6 {
  width: 50%;
}
.col-5 {
  width: 41.66666667%;
}
.col-4 {
  width: 33.33333333%;
}
.col-3 {
  width: 25%;
}
.col-2 {
  width: 16.66666667%;
}
.col-1 {
  width: 8.33333333%;
}
.col-auto {
  flex: 0 0 auto;
  max-width: none;
  width: auto;
}
.col-mx-auto {
  margin-left: auto;
  margin-right: auto;
}
.col-ml-auto {
  margin-left: auto;
}
.col-mr-auto {
  margin-right: auto;
}
@media  #{$breakpoint-not-small} {
  .col-ns-12,
  .col-ns-11,
  .col-ns-10,
  .col-ns-9,
  .col-ns-8,
  .col-ns-7,
  .col-ns-6,
  .col-ns-5,
  .col-ns-4,
  .col-ns-3,
  .col-ns-2,
  .col-ns-1,
  .col-ns-auto {
    flex: none;
  }
  .col-ns-12 {
    width: 100%;
  }
  .col-ns-11 {
    width: 91.66666667%;
  }
  .col-ns-10 {
    width: 83.33333333%;
  }
  .col-ns-9 {
    width: 75%;
  }
  .col-ns-8 {
    width: 66.66666667%;
  }
  .col-ns-7 {
    width: 58.33333333%;
  }
  .col-ns-6 {
    width: 50%;
  }
  .col-ns-5 {
    width: 41.66666667%;
  }
  .col-ns-4 {
    width: 33.33333333%;
  }
  .col-ns-3 {
    width: 25%;
  }
  .col-ns-2 {
    width: 16.66666667%;
  }
  .col-ns-1 {
    width: 8.33333333%;
  }
  .col-ns-auto {
    width: auto;
  }
  .hide-ns {
    display: none !important;
  }
  .show-ns {
    display: block !important;
  }
}
@media  #{$breakpoint-medium} {
  .col-m-12,
  .col-m-11,
  .col-m-10,
  .col-m-9,
  .col-m-8,
  .col-m-7,
  .col-m-6,
  .col-m-5,
  .col-m-4,
  .col-m-3,
  .col-m-2,
  .col-m-1,
  .col-m-auto {
    flex: none;
  }
  .col-m-12 {
    width: 100%;
  }
  .col-m-11 {
    width: 91.66666667%;
  }
  .col-m-10 {
    width: 83.33333333%;
  }
  .col-m-9 {
    width: 75%;
  }
  .col-m-8 {
    width: 66.66666667%;
  }
  .col-m-7 {
    width: 58.33333333%;
  }
  .col-m-6 {
    width: 50%;
  }
  .col-m-5 {
    width: 41.66666667%;
  }
  .col-m-4 {
    width: 33.33333333%;
  }
  .col-m-3 {
    width: 25%;
  }
  .col-m-2 {
    width: 16.66666667%;
  }
  .col-m-1 {
    width: 8.33333333%;
  }
  .col-m-auto {
    width: auto;
  }
  .hide-m {
    display: none !important;
  }
  .show-m {
    display: block !important;
  }
}
@media  #{$breakpoint-large} {
  .col-l-12,
  .col-l-11,
  .col-l-10,
  .col-l-9,
  .col-l-8,
  .col-l-7,
  .col-l-6,
  .col-l-5,
  .col-l-4,
  .col-l-3,
  .col-l-2,
  .col-l-1,
  .col-l-auto {
    flex: none;
  }
  .col-l-12 {
    width: 100%;
  }
  .col-l-11 {
    width: 91.66666667%;
  }
  .col-l-10 {
    width: 83.33333333%;
  }
  .col-l-9 {
    width: 75%;
  }
  .col-l-8 {
    width: 66.66666667%;
  }
  .col-l-7 {
    width: 58.33333333%;
  }
  .col-l-6 {
    width: 50%;
  }
  .col-l-5 {
    width: 41.66666667%;
  }
  .col-l-4 {
    width: 33.33333333%;
  }
  .col-l-3 {
    width: 25%;
  }
  .col-l-2 {
    width: 16.66666667%;
  }
  .col-l-1 {
    width: 8.33333333%;
  }
  .col-l-auto {
    width: auto;
  }
  .hide-l {
    display: none !important;
  }
  .show-l {
    display: block !important;
  }
}

            

以上で設定は終了しました。npm run productionを実行してコンパイルしましょう。 npm run production 本来、CSSフレームワークに他のフレームワークを導入することは難しいのでしょうが、TachyonsがUtility FirstのCSSフレームワークであったため、簡単に切り出して追加することができました。 コード量も46.0KBから48.9KBへと、わずか2.9KBの増加で済ませることができました。 Laravel Mixは処理をチェーンメソッドでつないで記述することができるので、非常にわかりやすく使いやすかったです。 すばらしい仕組みに感謝です。