はてなブログ用スライダー改訂版

11/15日の記事「バグ修正」にもとづき修正済みです。


少し前に作ったβ版程度の「はてなブログ用簡易スライダー」を、カルーセルにしたり、オートスタートなどのオプション指定できるようにしようと改良しようとしたのですが、ふと気づいてみれば、「はてなフォトライフ」の画像を挿入した時に、編集方法によって変換される HTMLが違うではありませんか!?

はてなブログ用簡易スライダーを作ってみた


ですので上のコードでは「はてな記法」や「Markdown」の編集方法では動きません。で、改訂版です。



fotolife記法では、imgspan でくくられる

これまで、あまりよく調べずに画像を挿入していたのですが、はてな記法や Markdown で画像を挿入した場合の f: で始まる構文は、fotolife記法というようです。


[f:id:ausnichts:20171112190223j:plain]


これが HTML ではどう変換されるかといいますと、次のように span でくくられます。

<span itemscope="" itemtype="http://schema.org/Photograph">
<img src="https://cdn-ak.f.st-hatena.com/images/fotolife/a/ausnichts/20171112/20171112190234.jpg" 
  alt="f:id:ausnichts:20171112190234j:plain"
  title="f:id:ausnichts:20171112190234j:plain"
  class="hatena-fotolife" itemprop="image">
</span>


その上、改行を打ったりしますとそのたびに空の <p></p> が入ったり、<p></p> でくくられたりします。公開した簡易スライダーでは、div 以下の画像要素が p でくくられている前提になっていますので、これでは動きません。


対応方法

で、こうしようと思います。

<div id="任意のスライダーの名前"></div> でくくった要素のうち、タグが <p> または <span> で、かつ内容が空でないもの以外の要素は削除していまいます。


デモ

次の fotolife記法でのデモです。

<div id="myslider">

[f:id:ausnichts:20171113140837j:plain]

[f:id:ausnichts:20171113140931j:plain]

[f:id:ausnichts:20171113140911j:plain]

</div>

画像の間の空行は、改行を入れても可能という意味のデモであり、画像を一列に挿入しても、改行しても問題ありません。


f:id:ausnichts:20171113140837j:plain f:id:ausnichts:20171113140931j:plain f:id:ausnichts:20171113140911j:plain


(注)モバイルのシミュレーションでは問題ないのですが、iphone 実機ではうまくいっていないようです。CSSの問題と思われ、カルーセル仕様の次回バージョンでは解消できると思います。

(注11/15)解消しているはずです。


使い方 Javascript & CSS

1.次の Javascript を「フッタ」に入れておきます。

<script>
function imzSlider(options) {
    var id = options.id,
        element = document.getElementById(id),
        slider = element.children,
        arrows  = options.arrows || true;

    for(var i=0; i<slider.length; i++){
        var tag = slider[i].tagName.toLowerCase();
        if((tag !== 'p' && tag !== 'span') || slider[i].innerHTML === '') {
            element.removeChild(slider[i]);
        }
    }
    element.classList.add('imzslider');

    var count   = element.getElementsByTagName('p').length || element.getElementsByTagName('span').length;
    if (count > 1) initial();
    if (arrows) showArrows();
    
    function initial() {
        // slider[0]は表示しておく
        for(var i=1; i<count; i++){
            slider[i].classList.add('hiddenslide');
        }
        
        var w = element.clientWidth;
        addStylesheetRules([
            ['#' + id + ' p',
                ['width', w + 'px']
            ],
            ['#' + id + ' p.hiddenslide',
                ['right', '-' + w + 'px']
            ],
            ['#' + id + ' span',
                ['width', w + 'px']
            ],
            ['#' + id + ' span.hiddenslide',
                ['right', '-' + w + 'px']
            ]
        ]);
    }

    function addStylesheetRules (rules) {
        var styleEl = document.createElement('style'),
            styleSheet;
        document.head.appendChild(styleEl);

        styleSheet = styleEl.sheet;

        for (var i = 0, rl = rules.length; i < rl; i++) {
            var j = 1, rule = rules[i], selector = rules[i][0], propStr = '';
            if (Object.prototype.toString.call(rule[1][0]) === '[object Array]') {
                rule = rule[1];
                j = 0;
            }

            for (var pl = rule.length; j < pl; j++) {
                var prop = rule[j];
                propStr += prop[0] + ':' + prop[1] + (prop[2] ? ' !important' : '') + ';\n';
            }

            styleSheet.insertRule(selector + '{' + propStr + '}', styleSheet.cssRules.length);
        }
    }
    
    function showArrows() {
        var divPrev = document.createElement('div');
        divPrev.classList.add('prevslide');
        divPrev.addEventListener('click', function(){imzSlide('p')}, false);

        var divNext = document.createElement('div');
        divNext.classList.add('nextslide');
        divNext.addEventListener('click', function(){imzSlide('n')}, false);

        element.appendChild(divPrev);
        element.appendChild(divNext);
        element.classList.add('noprev');
    }

    function imzSlide(n){
        for(var i=0; i<count; i++){
            if(slider[i].classList.contains('hiddenslide')){
                break;;
            }
        }

        if(n === 'n'){
            slider[i].classList.toggle('hiddenslide');
            if(i === 1) element.classList.remove('noprev');
            if(i === (count-1)) element.classList.add('nonext');
        }else{
            slider[i-1].classList.toggle('hiddenslide');
            if(i === 2) element.classList.add('noprev');
            if(i === count) element.classList.remove('nonext');
        }
    }

}
</script>


2.次の CSSを「デザインCSS」に追加します。

.imzslider {
  position: relative;
  overflow: hidden;
  display: inline-block; }
  .imzslider p, .imzslider span {
    -webkit-transition: right 400ms ease-in-out;
    transition: right 400ms ease-in-out;
    line-height: 0;
    position: absolute;
    right: 0;
    top: 0; }
    .imzslider p:first-child, .imzslider span:first-child {
      position: relative; }
  .imzslider .prevslide {
    display: block;
    position: absolute;
    background: rgba(255, 255, 255, 0.2);
    width: 6vw;
    height: 6vw;
    border-radius: 50%;
    top: 0;
    bottom: 0;
    left: 0;
    margin: auto;
    text-align: center;
    cursor: pointer; }
    .imzslider .prevslide::before {
      font-family: blogicon;
      content: "\f005";
      font-size: 5vw;
      color: rgba(255, 255, 255, 0.6);
      line-height: 6vw; }
  .imzslider.noprev .prevslide {
    display: none; }
  .imzslider .nextslide {
    display: block;
    position: absolute;
    background: rgba(255, 255, 255, 0.2);
    width: 6vw;
    height: 6vw;
    border-radius: 50%;
    top: 0;
    bottom: 0;
    right: 0;
    margin: auto;
    text-align: center;
    cursor: pointer; }
    .imzslider .nextslide::before {
      font-family: blogicon;
      content: "\f006";
      font-size: 5vw;
      color: rgba(255, 255, 255, 0.6);
      line-height: 6vw; }
  .imzslider.nonext .nextslide {
    display: none; }


3.記事にスライダー用の画像を好きなだけ挿入します。


4.次のように画像をdivでくくり、その下に Javascript を追加します。

<!-- idはオプションのidと一致させれば任意 -->
<div id="myslider">
[f:id:ausnichts:20171113140837j:plain]
[f:id:ausnichts:20171113140931j:plain]
[f:id:ausnichts:20171113140911j:plain]
</div>
<script>
window.addEventListener("load", function() {
  var slider = new imzSlider({
    id: 'myslider',
    arrows: true
  });
});
</script>


改良予定

  • スライドが終わりまで行ったら最初に戻るカルーセル仕様
  • オートスタート、ストップ
  • スライドの下に番号表示で個別選択


こうしたオプションを追加しようと思います。カルーセルにするためには、おそらく今の方法では難しく、他の方法を考えなくてはいけなさそうです。