jackmiwamiwa devblog

フロントエンドをメインに行ったことをまとめていくサイトになります。

stylesからdart-sassに変更した時に行なったこと・コード

stylusからdart-sassに変更したので、その時に対応したこと、stylusとscssのコードの比較に載せたものになります。

変更した箇所のコードについては以下になります。 github.com

stylusからdart-sassに変更した理由

  • stylintでstylusのインデント調整した後に編集を行うとエラーになるので、修正がつらい

github.com

  • 最近現場でもdart-sassを使う機会が増えたので、sassの勉強をしたい
  • stylusの方はあまり開発が進んでいないので、stylusを使う機会が減りそう。。

github.com

f:id:jackswim3411:20210807170938p:plain

github.com

f:id:jackswim3411:20210807171011p:plain

※ 画像は2021年8月7日時点

scssで使用したライブラリ

1. node-sass-glob-importer

scssで@import: 'scss/**/*.scss';のように記載を行うとまとめて読み込みを行なってくれるライブラリ

www.npmjs.com

2. stylelint

scssの設定など

www.npmjs.com

3. sass

dart-sassを使用するためのパッケージ

www.npmjs.com

scss, stylusのコード

ディレクト

styluys

❯ tree
.
├── foundation
│   ├── _debug.styl
│   ├── _default.styl
│   ├── _reset.styl
│   ├── barba
│   │   └── _animation.styl
│   ├── mixins
│   │   ├── _MixinFontSize.styl
│   │   ├── _MixinHoverAction.styl
│   │   ├── _MixinWrapperWidth.styl
│   │   └── _mediaquery.styl
│   └── variables
│       ├── _breakpoint.styl
│       ├── _color.styl
│       ├── _font.styl
│       └── _zindex.styl
├── layout
│   ├── _footer.styl
│   └── _header.styl
├── object
│   ├── components
│   │   └── _text.styl
│   ├── project
│   │   └── _top.styl
│   └── utility
│       └── _device.styl
└── style.styl

scss

❯ tree
.
├── foundation
│   ├── _debug.scss
│   ├── _default.scss
│   ├── _reset.scss
│   ├── barba
│   │   └── _animation.scss
│   ├── mixins
│   │   ├── _MixinFontSize.scss
│   │   ├── _MixinHoverAction.scss
│   │   ├── _MixinWrapperWidth.scss
│   │   └── _mediaquery.scss
│   └── variables
│       ├── _breakpoint.scss
│       ├── _color.scss
│       ├── _font.scss
│       └── _zindex.scss
├── layout
│   ├── _footer.scss
│   └── _header.scss
├── object
│   ├── components
│   │   └── _text.scss
│   ├── project
│   │   └── _top.scss
│   └── utility
│       └── _device.scss
└── style.scss

コードの内容について

foundation/_debug

stylus

/* **
 *
 * HTMLのセマンティックエラーを確認するためのcss
 * blog
 * https://ics.media/entry/200819/
 * code
 * https://github.com/ics-creative/200819_debug_css/blob/master/docs/debug.css
 *
 */
@keyframes blink-red
    0%
        outline-color red
    49.9%
        outline-color red
    50%
        outline-color transparent
    100%
        outline-color transparent

@keyframes blink-gold
    0%
        outline-color gold
    49.9%
        outline-color gold
    50%
        outline-color transparent
    100%
        outline-color transparent

ul > :not(li)
ol > :not(li)
    outline 2px solid red
    content '<ul>タグ、<ol>タグの直下に入れられるのは<li>タグだけです'
    animation blink-red 1s infinite

dl > :not(dt):not(dd):not(div)
    outline 2px solid red
    content '<dl>タグ、タグの直下に入れられるのは<dt>,<dd>,および<div>タグだけです'
    animation blink-red 1s infinite

a[name]
    outline 2px solid red
    content 'name属性はHTML5で廃止されました'
    animation blink-red 1s infinite

a[href='javascript:void(0)']
    outline 2px solid gold
    content '<a>タグは移動するためだけに使用するべきです'
    animation blink-gold 1s infinite

a[target=_blank]:not([rel='noreferrer noopener'])
    outline 2px solid gold
    content 'target="_blank"の場合は悪用を防ぐためにもrel="noreferrer noopener"の使用を推奨します'
    animation blink-gold 1s infinite

img:not([alt])
img[alt='']
    display block
    outline 2px solid gold
    animation blink-gold 1s infinite

img:not([width])
img[width='']
img:not([height])
img[height='']
    display block
    outline 2px solid gold
    animation blink-gold 1s infinite

:root iframe:nth-of-type(4)
    outline 2px solid gold
    content '連続して4つ以上のiframeが設置されています。iframeが複数あるとパフォーマンスに影響を与えます'
    animation blink-gold 1s infinite

time:not([datetime])
time[datetime='']
    outline 2px solid gold
    content 'datetime属性がない場合、タグ内に妥当な値が入力されていますか?'
    animation blink-gold 1s infinite

time:not([datetime]) *
time[datetime=''] *
    outline 2px solid red
    content 'datetime属性がない場合、タグ内に子孫要素をもってはいけません'
    animation blink-red 1s infinite

font
center
frame
blink
marquee
*[align]
*[color]
*[bgcolor]
*[border]
*[background]
    outline 2px solid red
    content '古いタグや属性が使用されています。古いタグの使用はやめ、装飾はCSSで行うようにしましょう'
    animation blink-red 1s infinite

hgroup > :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6)
    outline 2px solid red
    content 'hgroupタグ内で許可されているのはh1~h6タグです'
    animation blink-red 1s infinite

table > * ~ caption
    outline 2px solid red
    content 'capptionタグはtableタグの最初の子要素として配置しなくてはなりません'
    animation blink-red 1s infinite

br + br
    display none

scss

/* **
 *
 * HTMLのセマンティックエラーを確認するためのcss
 * blog
 * https://ics.media/entry/200819/
 * code
 * https://github.com/ics-creative/200819_debug_css/blob/master/docs/debug.css
 *
 */
@keyframes blink-red {
  0% {
    outline-color: red;
  }
  49.9% {
    outline-color: red;
  }
  50% {
    outline-color: transparent;
  }
  100% {
    outline-color: transparent;
  }
}

@keyframes blink-gold {
  0% {
    outline-color: gold;
  }
  49.9% {
    outline-color: gold;
  }
  50% {
    outline-color: transparent;
  }
  100% {
    outline-color: transparent;
  }
}

ul > :not(li),
ol > :not(li) {
  content: '<ul>タグ、<ol>タグの直下に入れられるのは<li>タグだけです';
  outline: 2px solid red;
  animation: blink-red 1s infinite;
}

dl > :not(dt):not(dd):not(div) {
  content: '<dl>タグ、タグの直下に入れられるのは<dt>,<dd>,および<div>タグだけです';
  outline: 2px solid red;
  animation: blink-red 1s infinite;
}

a[name] {
  content: 'name属性はHTML5で廃止されました';
  outline: 2px solid red;
  animation: blink-red 1s infinite;
}

a[href='javascript:void(0)'] {
  content: '<a>タグは移動するためだけに使用するべきです';
  outline: 2px solid gold;
  animation: blink-gold 1s infinite;
}

a[target='_blank']:not([rel='noreferrer noopener']) {
  content: 'target="_blank"の場合は悪用を防ぐためにもrel="noreferrer noopener"の使用を推奨します';
  outline: 2px solid gold;
  animation: blink-gold 1s infinite;
}

img:not([alt]),
img[alt=''] {
  display: block;
  outline: 2px solid gold;
  animation: blink-gold 1s infinite;
}

img:not([width]),
img[width=''],
img:not([height]),
img[height=''] {
  display: block;
  outline: 2px solid gold;
  animation: blink-gold 1s infinite;
}

:root iframe:nth-of-type(4) {
  content: '連続して4つ以上のiframeが設置されています。iframeが複数あるとパフォーマンスに影響を与えます';
  outline: 2px solid gold;
  animation: blink-gold 1s infinite;
}

time:not([datetime]),
time[datetime=''] {
  content: 'datetime属性がない場合、タグ内に妥当な値が入力されていますか?';
  outline: 2px solid gold;
  animation: blink-gold 1s infinite;
}

time:not([datetime]) *,
time[datetime=''] * {
  content: 'datetime属性がない場合、タグ内に子孫要素をもってはいけません';
  outline: 2px solid red;
  animation: blink-red 1s infinite;
}

font,
center,
frame,
blink,
marquee,
*[align],
*[color],
*[bgcolor],
*[border],
*[background] {
  content: '古いタグや属性が使用されています。古いタグの使用はやめ、装飾はCSSで行うようにしましょう';
  outline: 2px solid red;
  animation: blink-red 1s infinite;
}

hgroup > :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) {
  content: 'hgroupタグ内で許可されているのはh1~h6タグです';
  outline: 2px solid red;
  animation: blink-red 1s infinite;
}

table > * ~ caption {
  content: 'capptionタグはtableタグの最初の子要素として配置しなくてはなりません';
  outline: 2px solid red;
  animation: blink-red 1s infinite;
}

br + br {
  display: none;
}

foundation/_default

stylus

html
body
    background MixinColorPalette(back)

body
    color MixinColorPalette(text)
    font-size (16 / FontSize_Default) * 100%
    font-family FontFamily_Default
    text-rendering optimizeLegibility

button
    cursor pointer

a
    color inherit
    text-decoration none

main
    display block
    min-width 375px // viewport-extra検証用のため、仮追加
    height 200vh // スクロールするため、仮追加

[data-whatinput='mouse'] *:focus
[data-whatinput='touch'] *:focus
    outline none

scss

@use "sass:math";
html,
body {
  background: MixinColorPalette('back');
  background: #fff;
}

body {
  color: MixinColorPalette(text);
  font-size: percentage(math.div(16, $FontSize_Default));
  font-family: $FontFamily_Default;
  text-rendering: optimizeLegibility;
}

button {
  cursor: pointer;
}

a {
  color: inherit;
  text-decoration: none;
}

main {
  display: block;
  min-width: 375px; // viewport-extra検証用のため、仮追加
  height: 200vh; // スクロールするため、仮追加
}

[data-whatinput='mouse'] *:focus,
[data-whatinput='touch'] *:focus {
  outline: none;
}

foundation/_reset

stylus

*
*::before
*::after
    box-sizing border-box

ul
ol
    padding 0
    list-style none

body
h1
h2
h3
h4
p
ul
ol
li
figure
figcaption
blockquote
dl
dd
    margin 0

body
    line-height 1.5
    scroll-behavior smooth
    text-rendering optimizeSpeed

a:not([class])
    text-decoration-skip-ink auto

img
    display block
    max-width 100%

article > * + *
    margin-top 1em

input
button
textarea
select
    margin 0
    padding 0
    border none
    border-radius 0
    background none
    background-color transparent
    color inherit
    font inherit
    appearance none

// @stylint off
@media (prefers-reduced-motion reduce)
    *
        transition-duration .01ms !important
        animation-duration .01ms !important
        animation-iteration-count 1 !important
        scroll-behavior auto !important

scss

*,
*::before,
*::after {
  box-sizing: border-box;
}

ul,
ol {
  padding: 0;
  list-style: none;
}

body,
h1,
h2,
h3,
h4,
p,
ul,
ol,
li,
figure,
figcaption,
blockquote,
dl,
dd {
  margin: 0;
}

body {
  line-height: 1.5;
  scroll-behavior: smooth;
  text-rendering: optimizeSpeed;
}

a:not([class]) {
  text-decoration-skip-ink: auto;
}

img {
  display: block;
  max-width: 100%;
}

article > * + * {
  margin-top: 1em;
}

input,
button,
textarea,
select {
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  background: none;
  background-color: transparent;
  border: none;
  border-radius: 0;
  appearance: none;
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

barba/_animation

stylus

.barba-leave-active
.barba-enter-active
    transition opacity .4s ease

.barba-leave
    opacity 1

.barba-enter
    opacity 0

.barba-leave-to
    opacity 0

.barba-enter-to
    opacity 1

scss

.barba-leave-active,
.barba-enter-active {
  transition: opacity 0.4s ease;
}

.barba-leave {
  opacity: 1;
}

.barba-enter {
  opacity: 0;
}

.barba-leave-to {
  opacity: 0;
}

.barba-enter-to {
  opacity: 1;
}

mixins/_MixinFontSize

stylus

MixinFontSize(font, lineheight = defaule)
    Mixinfont = (font / FontSize_Default)
    if (lineheight == defaule)
        Mixinlineheight = 1.6666
    else if (lineheight == normal)
        Mixinlineheight = normal
    else
        Mixinlineheight = (lineheight / font)
    font-size Mixinfont rem
    line-height Mixinlineheight

scss

@use "sass:math";
@mixin MixinFontSize($fontSize, $lineheight: 'default') {
  $Mixinfont: math.div($fontSize, $FontSize_Default);
  $Mixinlineheigh: 1.6666;
  @if $lineheight == 'default' {
    $Mixinlineheigh: 1.6666;
  } @else if $lineheight == 'normal' {
    $Mixinlineheigh: 'normal';
  } @else {
    $Mixinlineheigh: math.div($lineheight, $fontSize);
  }
  font-size: #{$Mixinfont}rem;
  line-height: #{$Mixinlineheigh};
}

mixins/_MixinHoverAction

stylus

MixinHoverAction(hoverTime = 0)
    @media (hover hover)
        &:hover
            transition hoverTime s
            {block}
    @media all and (-ms-high-contrast none)
        &:hover
            transition hoverTime s
            {block}
    &:active
        {block}

scss

@mixin MixinHoverAction($hoverTime: 0) {
  @media (hover: hover) {
    &:hover {
      transition: #{$hoverTime}s;
      @content;
    }
  }
  @media all and (-ms-high-contrast: none) {
    &:hover {
      transition: #{$hoverTime}s;
      @content;
    }
  }
  &:active {
    @content;
  }
}

mixins/_MixinWrapperWidth

stylus

MixinWrapperWidth(contentwidth, globalwidth = MixinBreakPoint(MAXPC), position = center)
    if (globalwidth == full)
        max-width 100%
        width percentage((contentwidth / MixinBreakPoint(MAXPC)))
    else
        max-width contentwidth
        width percentage((contentwidth / globalwidth))
    if (position == center)
        margin-right auto
        margin-left auto
    else if (position == left)
        margin-right auto
    else if (positon == right)
        margin-left auto
    +sp-only()
        if (globalwidth == MixinBreakPoint(MAXPC) || (globalwidth == full))
            width calc(100% - 40px)
        else
            width 100%

scss

@use "sass:math";
@mixin MixinWrapperWidth($contentwidth, $globalwidth: 1920, $position: center) {
  @if $globalwidth == 'full' {
    width: percentage(math.div($contentwidth, 1920));
    max-width: 100%;
  } @else {
    width: percentage(math.div($contentwidth, $globalwidth));
    max-width: $contentwidth;
  }
  @if $position == 'center' {
    margin-right: auto;
    margin-left: auto;
  } @else if $position == 'left' {
    margin-right: auto;
  } @else if $position == 'right' {
    margin-left: auto;
  }
  @include sp-only() {
    @if $globalwidth == MixinBreakPoint('MAXPC') or $globalwidth == 'full' {
      width: calc(100% - 40px);
    } @else {
      width: 100%;
    }
  }
}

mixins/_mediaquery

stylus

// pcの最大幅(1920px)になったら
max-pc()
    @media screen and (min-width MixinBreakPoint(MAXPC))
        {block}

// 通常のpc用(1560px以下)
normal-pc()
    @media screen and (max-width MixinBreakPoint(PC_CONTENT))
        {block}

// 通常のpc用(1280px以下)
min-pc()
    @media screen and (max-width MixinBreakPoint(PC))
        {block}

// 通常のpcとspの切り替え(pc用)
pc-only()
    @media screen and (min-width MixinBreakPoint(TABLET))
        {block}

// 通常のpcとspの切り替え(sp用)
sp-only()
    @media screen and (max-width MixinBreakPoint(TABLET))
        {block}

// スマートフォンのみ別で対応したい場合(767px以下)
min-sp()
    @media screen and (max-width MixinBreakPoint(SMARTPHONE))
        {block}

// iphone5のみ別で対応したい場合
iphone5()
    @media screen and (max-width MixinBreakPoint(SMALL))
        {block}

// カスタムブレイクポイント
custom-breakpoint(value, maxmin = max)
    if (maxmin == sp || max)
        maxmin = max
    else if (manmin == pc || min)
        maxmin = min
    @media screen and ({maxmin}-width value px)
        {block}

scss

// pcの最大幅(1920px)になったら
@mixin max-pc() {
  @media screen and (min-width: MixinBreakPoint('MAXPC')) {
    @content;
  }
}

// 通常のpc用(1560px以下)
@mixin normal-pc() {
  @media screen and (min-width: MixinBreakPoint('PC_CONTENT')) {
    @content;
  }
}
// 通常のpc用(1280px以下)
@mixin min-pc() {
  @media screen and (min-width: MixinBreakPoint('PC')) {
    @content;
  }
}

// 通常のpcとspの切り替え(pc用)
@mixin pc-only() {
  @media screen and (min-width: MixinBreakPoint('TABLET')) {
    @content;
  }
}

// 通常のpcとspの切り替え(sp用)
@mixin sp-only() {
  @media screen and (max-width: MixinBreakPoint('TABLET')) {
    @content;
  }
}

// スマートフォンのみ別で対応したい場合(767px以下)
@mixin min-sp() {
  @media screen and (max-width: MixinBreakPoint('SMARTPHONE')) {
    @content;
  }
}

// iphone5のみ別で対応したい場合
@mixin iphone5() {
  @media screen and (max-width: MixinBreakPoint('SMALL')) {
    @content;
  }
}

// カスタムブレイクポイント
@mixin custom-breakpoint($value, $maxmin: 'max') {
  @if $maxmin == 'max' {
    $maxmin: 'max';
  } @else {
    $maxmin: 'min';
  }
  @media screen and (#{$maxmin}-width: #{$value}px) {
    @content;
  }
}

variables/_breakpoint

stylus

BREAK_POINT = {
    MAXPC: 1920,
    PC_CONTENT: 1560,
    PC: 1280,
    TABLET: 1023,
    SMARTPHONE: 767,
    SMALL: 320
}
BREAK_POINT_CUSTOM = 1180

MixinBreakPoint(deviceSize)
    return (BREAK_POINT[deviceSize]) px

scss

$BREAK_POINT: (
  MAXPC: 1920,
  PC_CONTENT: 1560,
  PC: 1280,
  TABLET: 1023,
  SMARTPHONE: 767,
  SMALL: 320,
);
$BREAK_POINT_CUSTOM: 1180;

@function MixinBreakPoint($deviceSize) {
  @return map-get($BREAK_POINT, $deviceSize) + 'px';
}

variables/_color

stylus

COLOR_Palette = {
    default: {
        back: #fff,
        text: #333
    },
    footer: {
        text: #ddd
    }
}

MixinColorPalette(type, pattern = default)
    return COLOR_Palette[pattern][type]

scss

$COLOR_Palette: (
  default: (
    back: #fff,
    text: #333,
  ),
  footer: (
    text: #ddd,
  ),
);
@function MixinColorPalette($type, $pattern: 'default') {
  $object: map-get($COLOR_Palette, $pattern);
  @return map-get($object, $type);
}

variables/_font

stylus

FontSize_Default = 16
FontFamily_Default = 'Helvetica Neue', Arial, 'Hiragino Kaku Gothic ProN', 'Hiragino Sans', Meiryo, sans-serif

scss

$FontSize_Default: 16;
$FontFamily_Default: 'Helvetica Neue', Arial, 'Hiragino Kaku Gothic ProN', 'Hiragino Sans', Meiryo, sans-serif;

variables/_zindex

stylus

Z_common = header navModel
Z_top = mainMv mainKv mainKv2
Z_about = aboutMv aboutKv
Z_allcontent = Z_top Z_about Z_common
Z_backContent = -1

zIndex(name)
    zNumber = 0
    if (name == 'back')
        return Z_backContent
    for contentAry in Z_allcontent
        for contentName in contentAry
            zNumber = zNumber + 1
            if (contentName == name)
                return zNumber
    return false

scss

$Z_common: header, navModel;
$Z_top: mainMv, mainKv, mainKv2;
$Z_about: aboutMv, aboutKv;
$Z_allcontent: $Z_top, $Z_about, $Z_common;
$Z_backContent: -1;

@function zIndex($name) {
  $zNumber: 0;
  @if $name == 'back' {
    @return $Z_backContent;
  }
  @each $contentAry in $Z_allcontent {
    @each $contentName in $contentAry {
      $zNumber: $zNumber + 1;
      @if $contentName == $name {
        @return $zNumber;
      }
    }
  }
  @return false;
}

layout/_footer

stylus

small
    color MixinColorPalette(text, footer)

scss

small {
  color: MixinColorPalette('text', 'footer');
}

layout/_header

stylus

.l-header
    margin 0 auto
    width calc(100% - 40px)

.l-header__Title
    color MixinColorPalette(text)

scss

.l-header {
  width: calc(100% - 40px);
  margin: 0 auto;
}

.l-header__Title {
  color: MixinColorPalette(text);
}

object/components/_text

stylus

.c-text
    MixinFontSize 15

scss

.c-text {
  @include MixinFontSize(15);
}

object/project/_top

stylus

.p-top
    z-index zIndex(header)
    display flex
    MixinWrapperWidth 1280px full
    MixinFontSize 14 40
    +custom-breakpoint(1000)
        font-size 20px

.img-back
    width 237px
    height 153px
    background url('/assets/img/sample.png')
    background-size cover

scss

.p-top {
  z-index: zIndex('header');
  display: flex;
  @include MixinWrapperWidth(1280, 'full');
  @include MixinFontSize(14, 40);
  @include custom-breakpoint(1000) {
    font-size: 20px;
  }
}

.img-back {
  width: 237px;
  height: 153px;
  background: url('/assets/img/sample.png');
  background-size: cover;
}

object/utility/_device

stylus

.u-is-pc
    +sp-only()
        display none !important

.u-is-sp
    +pc-only()
        display none !important

scss

.u-is-pc {
  @include sp-only() {
    display: none !important;
  }
}

.u-is-sp {
  @include pc-only() {
    display: none !important;
  }
}

style

stylus

// @import './foundation/_debug'
@import './foundation/variables/*'
@import './foundation/mixins/*'
@import './foundation/_reset'
@import './foundation/_default'
@import './foundation/barba/*'
@import './layout/*'
@import './object/**/*'

scss

// @import './foundation/debug'
@import './foundation/variables/*';
@import './foundation/mixins/*';
@import './foundation/reset';
@import './foundation/default';
@import './foundation/barba/*';
@import './layout/*';
@import './object/components/*';
@import './object/project/*';
@import './object/utility/*';