chlonolog

web, digital gadgets, and more.

Hexoテーマを自作しました

サイトで使用しているHexoテーマを一新しました。

Bootstapも嫌いじゃないんだけど……

ずっとBootstrapベースのHexoテーマに手を入れたものを使用していました。
Bootstrapの見た目は割と好きだったのですが、いかんせん必要のない装飾が結構多いんですよね。だから無駄に上書きが増えて、非常に分かりづらくなる傾向がありまして……。
「これどこで設定されてんの? え、Bootstrap? またかよ」ということが何度もあり、ちょっと鬱陶しくなってきたので、テーマをいちから作ることにしました。


CSSフレームワークの選定

CSSフレームワーク、最近はいっぱいあるんですね。
群雄割拠の中からいろいろ調べた結果、BootstrapからBulmaに変更しました。やはり時代はFlexboxなのかなと。え? もう枯れてる? そんなー。
ひたすらdivをfloatして頑張っていた世代なので、Flexboxは目からウロコでした。まじか神じゃんすげえ、みたいな。いやーいい時代になりました。

Flexboxもですが、Bulmaは見た目もフラットですっきりしていて、何より変数ヘルパーが分かりやすいのが決め手でした。サイトを見ればだいたいの変数が列挙されていて、それでも見つからなければファイルを見ればすぐ見つけられる。なんと素晴らしい。

画面デザインについては、

  • PCで表示した際は右側にメニューを常時表示
  • スマホで表示した際は右側のメニューをドロワーとして表示

という動作が実装できたので満足です。

webフォント

どうにも重くなりがちで避けていたFont Awesomeでしたが、画面上で使用している文字だけをサブセット化する仕組みをGulpで組めたので、晴れて使用を再開しました。
Font Awesomeに含まれないはてなブックマークのアイコンについては、Ligature Symbolsをサブセット化して対応しました。いやーほんとに便利ですなサブセット。

JavaScript周り

画面表示時のふわっとしたやつ

画面表示時に、jquery.inviewを使ってエフェクトを追加しています。
あちこちで見かけるふわっとした表示、どうやってやるのかなとずっと気になっていたんです。いい加減流行も去った気もしますが、個人的にやってみたかったので採用しました。

やったことといえば「jquery.inview.js」を読み込み、JavaScriptとCSSに設定を追加しただけです。(うちはCoffeeScriptとSASSですが)

CoffeeScript

(($) ->
  $('article').one 'inview', (event, isInView) ->
    if isInView
      $(@).stop().addClass('scrollin')

  $('.image').one 'inview', (event, isInView) ->
    if isInView
      $(@).stop().addClass('scrollin')
) jQuery

SASS

.image,
article
  opacity: 0
  transform: translate(0, 50px)

  &.scrollin
    opacity: 1
    transform: translate(0, 0)
    transition: .3s

要は、画面内に入ったら独自クラスを追加するだけです。すごく簡単ですね。

画面から消えた段階でクラスを削除すれば何度でもエフェクトさせられますが、さすがに鬱陶しくなるので一度でも表示したらそのままにしてあります。
浮き上がるような動作については、飽きたら削除すると思います。基本的にはopacityだけでいいかな。

画面上部/下部への移動

jquery.inviewは、画面上部/下部へ移動するリンク(画面右下にあるやつ)の表示切り替えでも使用しています。
画面周りだけ抜き出すとこんな感じ。

# 本文部分が表示されたとき
(($) ->
  $('.articles').on 'inview', (event, isInView) ->
    $('#pagetop')
      .removeClass 'hide'
      .stop()
      .addClass 'up'
    $('#pagebottom')
      .removeClass 'hide'

  # ヒーローが表示されたとき
  $('.hero').on 'inview', (event, isInView) ->
    $('#pagebottom')
      .removeClass 'hide'
    if isInView
      $('#pagetop')
        .addClass 'hide'
        .stop()
        .removeClass 'up'
    else
      $('#pagetop')
        .removeClass 'hide'
        .stop()
        .addClass 'up'

  # フッタが表示されたとき
  $('.footer').on 'inview', (event, isInView) ->
    if isInView
      $('#pagebottom').addClass 'hide'
      $('#pagetop').removeClass 'up'
    else
      $('#pagetop').addClass 'up'
      $('#pagebottom').removeClass 'hide'
) jQuery

.articlesへの設定は蛇足な気もしますが、中間地点でリロードすると表示が消えてしまったりすることがあったので、割としつこめに書いています。

上下移動の動作部分はこちら。

(($) ->
  # 画面の最上部/最下部へ移動
  scrollAction = (target) ->
    $('body,html').animate
      scrollTop: target
    , 500
    false;

  $('#pagetop').on
    mouseenter: ->
      $(@).css opacity: '1'
    mouseleave: ->
      $(@).css opacity: '.4'
    click: ->
      scrollAction 0
      $(@).css opacity: '.4'
      false

  $('#pagebottom').on
    mouseenter: ->
      $(@).css opacity: '1'
    mouseleave: ->
      $(@).css opacity: '.4'
    click: ->
      scrollAction $(document).height()
      $(@).css opacity: '.4'
      false
) jQuery

mouseenter/mouseleaveの動作は、元々CSSの:hoverで書いていました。
しかし1になったまま戻らないことがちょくちょくあったため、最終的にJavaScriptに任せることにしました。

検索ページのフィルタリング

検索ページにはMixItUpを使いました。
カテゴリ・タグ・アーカイブで同一の処理を使用しているため少々ごちゃごちゃしていますが……

(($) ->
  mixer = null
  $(document).ready ->
    if $('.search-logs').length
      mixer = mixitup '.search-logs', {
        animation: {
          enable: false
        },
        selectors:
          target: '.archive-post, .archive-head, .archive-tag'
        callbacks:
          onMixFail: ->
            $('.archive-result').text '該当するアーカイブはありませんでした。'
          onMixEnd: ->
            $('.archive-result').text ''
      }

  $('#filter-form').bind 'change keyup', ->
    if $('.search-archives').length
      # アーカイブは先頭一致
      arg = '[data-value^="' + $(this).val().toLowerCase() + '"]'
    else
      # それ以外は部分一致
      arg = '[data-value*="' + $(this).val().toLowerCase() + '"]'

    if $(this).val() == ''
      mixer.filter 'all'
      $('#filter-form').val ''
    else
      mixer.filter arg

    $('.form-clear').click ->
      mixer.filter 'all'
      $('#filter-form').val ''
) jQuery

多彩なエフェクトはMixItUpの売りですが、今回は切ってあります。

昔は手動で書いていたものがプラグインひとつで簡単に設定できてしまうことに、時代の流れを感じました。

Hexo周り

テンプレートの言語

いずれはPugにしたいと思いつつ、学習コストの関係で現状はEJSです。

PandocからMarkdown-itに乗り換えました

HexoのMarkdown拡張にはPandocを使っていましたが、このたび拡張のしやすいMarkdown-itHexoプラグイン)へ乗り換えました。
追加したプラグインはこんな感じです。

ルビ(markdown-it-ruby

彼らの{人生|じんせい}

彼らの人生じんせい

キー(markdown-it-kbd

[[Command]] + [[Space]]

Command + Space

取り消し線(markdown-it-strikethrough-alt

--取り消し線--

取り消し線

略語(markdown-it-abbr

*[HTML]: Hyper Text Markup Language
*[W3C]:  World Wide Web Consortium
The HTML specification
is maintained by the W3C.

The HTML specification
is maintained by the W3C.

div(markdown-it-div

::: . message-body .is-info
Message is here.
:::

Message is here.

独自属性の追加(markdown-it-attrs

##### 属性をつけたヘッダ {.has-text-success}
属性をつけたpタグ {data-toggle=modal}
属性をつけたヘッダ

属性をつけたpタグ

Font Awesome(markdown-it-fontawesome

Hello World! :fa-flag:

Hello World!

脚注(markdown-it-footnote

これは脚注の参照です[^1]。脚注は自動的に文末へ出力されます。
[^1]: これは脚注です。

これは脚注の参照です[1]。脚注は自動的に文末へ出力されます。

定義リスト(markdown-it-deflist

Term 1
:   Definition 1

Term 2 with *inline markup*
:   Definition 2
        { some code, part of Definition 2 }
    Third paragraph of definition 2.
Term 1
Definition 1
Term 2 with inline markup
Definition 2
{ some code, part of Definition 2 }
Third paragraph of definition 2.

  1. これは脚注です。

コメント

© 2018 chlono