はてなブログで以下のブログ記事を作るにあたって、画像比較スライダーのCocoenを導入した。
試行錯誤
Visual Studio Codeを使いながら試行錯誤した。なお、このブログではMarkdown記法(1、2)を使用している。
Before/Afterのラベルを貼れるのが良いと思って、最初はBeerSliderを試したが、Safariで動かないと教えてもらったので止めた。
次に試したのがCocoenだった。
CocoenはGitHubよりも紹介しているブログ記事の方が分かりやすかった。
JQuery-Images-Compareとbefore-after.jsも試したが、上手く行かなかったので止めた。
Cocoenを導入する
以下、Cocoenを導入するために実装したJavaScript、CSS、HTMLコードになる。
JavaScript
はてなブログの管理画面の「デザイン→カスタマイズ→フッタ」に以下のJavaScriptのコードを貼り付けた。コードの内容はCocoenを紹介したブログ記事と同じである。
<script> !function(e) { if ("object" == typeof exports && "undefined" != typeof module) module.exports = e(); else if ("function" == typeof define && define.amd) define([], e); else { var t; t = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : this, t.Cocoen = e() } }(function() { return function e(t, n, i) { function s(o, a) { if (!n[o]) { if (!t[o]) { var l = "function" == typeof require && require; if (!a && l) return l(o, !0); if (r) return r(o, !0); var d = new Error("Cannot find module '" + o + "'"); throw d.code = "MODULE_NOT_FOUND", d } var h = n[o] = { exports: {} }; t[o][0].call(h.exports, function(e) { var n = t[o][1][e]; return s(n ? n : e) }, h, h.exports, e, t, n, i) } return n[o].exports } for (var r = "function" == typeof require && require, o = 0; o < i.length; o++) s(i[o]); return s }({ 1: [function(e, t, n) { "use strict"; function i(e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") } var s = Object.assign || function(e) { for (var t = 1; t < arguments.length; t++) { var n = arguments[t]; for (var i in n) Object.prototype.hasOwnProperty.call(n, i) && (e[i] = n[i]) } return e }, r = function() { function e(e, t) { for (var n = 0; n < t.length; n++) { var i = t[n]; i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(e, i.key, i) } } return function(t, n, i) { return n && e(t.prototype, n), i && e(t, i), t } }(), o = function() { function e(t, n) { i(this, e), this.options = s({}, e.defaults, n), this.element = t || document.querySelector(".cocoen"), this.init() } return r(e, [{ key: "init", value: function() { this.createElements(), this.addEventListeners(), this.dimensions() } }, { key: "createElements", value: function() { var e = document.createElement("span"); e.className = this.options.dragElementSelector.replace(".", ""), this.element.appendChild(e) var t = document.createElement("div"), n = this.element.querySelector("img:first-child"); t.appendChild(n.cloneNode(!0)), n.parentNode.replaceChild(t, n), this.dragElement = this.element.querySelector(this.options.dragElementSelector), this.beforeElement = this.element.querySelector("div:first-child"), this.beforeImage = this.beforeElement.querySelector("img") } }, { key: "addEventListeners", value: function() { this.element.addEventListener("click", this.onTap.bind(this)), this.element.addEventListener("mousemove", this.onDrag.bind(this)), this.element.addEventListener("touchmove", this.onDrag.bind(this)), this.dragElement.addEventListener("mousedown", this.onDragStart.bind(this)), this.dragElement.addEventListener("touchstart", this.onDragStart.bind(this)), window.addEventListener("mouseup", this.onDragEnd.bind(this)), window.addEventListener("resize", this.dimensions.bind(this)) } }, { key: "dimensions", value: function() { this.elementWidth = parseInt(window.getComputedStyle(this.element).width, 10), this.elementOffsetLeft = this.element.getBoundingClientRect().left + document.body.scrollLeft, this.beforeImage.style.width = this.elementWidth + "px", this.dragElementWidth = parseInt(window.getComputedStyle(this.dragElement).width, 10), this.minLeftPos = this.elementOffsetLeft + 10, this.maxLeftPos = this.elementOffsetLeft + this.elementWidth - this.dragElementWidth - 10 } }, { key: "onTap", value: function(e) { e.preventDefault(), this.leftPos = e.pageX ? e.pageX : e.touches[0].pageX, this.requestDrag() } }, { key: "onDragStart", value: function(e) { e.preventDefault(); var t = e.pageX ? e.pageX : e.touches[0].pageX, n = this.dragElement.getBoundingClientRect().left + document.body.scrollLeft; this.posX = n + this.dragElementWidth - t, this.isDragging = !0 } }, { key: "onDragEnd", value: function(e) { e.preventDefault(), this.isDragging = !1 } }, { key: "onDrag", value: function(e) { e.preventDefault(), this.isDragging && (this.moveX = e.pageX ? e.pageX : e.touches[0].pageX, this.leftPos = this.moveX + this.posX - this.dragElementWidth, this.requestDrag()) } }, { key: "drag", value: function() { this.leftPos < this.minLeftPos ? this.leftPos = this.minLeftPos : this.leftPos > this.maxLeftPos && (this.leftPos = this.maxLeftPos); var e = this.leftPos + this.dragElementWidth / 2 - this.elementOffsetLeft; e /= this.elementWidth; var t = 100 * e + "%"; this.dragElement.style.left = t, this.beforeElement.style.width = t, this.options.dragCallback && this.options.dragCallback(e) } }, { key: "requestDrag", value: function() { window.requestAnimationFrame(this.drag.bind(this)) } }]), e }(); o.defaults = { dragElementSelector: ".cocoen-drag", dragCallback: null }, t.exports = o }, {}] }, {}, [1])(1) }); </script> <script> document.querySelectorAll('.cocoen').forEach(function(element){ new Cocoen(element); }); /* The MIT License (MIT) */ /* Copyright (c) 2015 Koen Romers */ /* https://github.com/koenoe/cocoen/blob/main/LICENSE */ </script>
CSS
はてなブログの管理画面の「デザイン→カスタマイズ→デザインCSS」に以下のCSSのコードを貼り付けた。
.cocoen-drag::before
と.cocoen-drag::after
に分けてborder
プロパティを調整して左右の外側を向く三角形を2つ作る事で、左右にスライドして動かすというのを分かりやすくしたつもりである。border
プロパティを調整するために以下の解説を参考にした。
.cocoen { box-sizing: border-box; cursor: pointer; line-height: 0; margin: 0; overflow: hidden; padding: 0; position: relative; -webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; user-select: text; } .cocoen * { box-sizing: inherit; } .cocoen ::after, .cocoen ::before { box-sizing: inherit; } .cocoen img, .cocoen picture > img { max-width: none; } .cocoen > img, .cocoen > picture > img { display: block; width: 100%; } .cocoen > div:first-child, picture .cocoen > div { height: 100%; left: 0; overflow: hidden; position: absolute; top: 0; width:50%; } .cocoen-drag { background: #fff; bottom: 0; cursor: ew-resize; left: 50%; margin-left: 0px; position: absolute; top: 0; width:2px; } /* 左向きの三角形 */ .cocoen-drag::before { border-top: 18px solid transparent; border-bottom: 18px solid transparent; border-right: 14px solid #fff; content: ''; height: 30px; right: 10%; margin-right: 6px; margin-top: -18px; position: absolute; top: 50%; width: 8px; } /* 右向きの三角形 */ .cocoen-drag::after { border-top: 18px solid transparent; border-bottom: 18px solid transparent; border-left: 14px solid #fff; content: ''; height: 30px; left: 10%; margin-left: 6px; margin-top: -18px; position: absolute; top: 50%; width: 8px; /* The MIT License (MIT) */ /* Copyright (c) 2015 Koen Romers */ /* https://github.com/koenoe/cocoen/blob/main/LICENSE */ }
ブログ記事内の本文内HTML
はてなフォトライフの個別の画像URLを右クリックメニューでコピーして<img src="">
に貼り付ける。
<!--はてなブログのMarkdown記法で使う場合--> <figure class="figure-image figure-image-fotolife"> <div class="cocoen"> <img src="<!--左側の画像URL-->"> <img src="<!--右側の画像URL-->"> </div> <figcaption><!--画像キャプションは任意、無くても良い--></figcaption> </figure>
Cocoenに限らず、はてな記法でブログの本文にHTMLコードを挿入する時は> <
の間にHTMLコードを挟んで入力する必要がある。
<!--はてなブログのはてな記法で使う場合--> ><figure class="figure-image figure-image-fotolife"> <div class="cocoen"> <img src="<!--左側の画像URL-->"> <img src="<!--右側の画像URL-->"> </div> <figcaption><!--画像キャプションは任意、無くても良い--></figcaption> </figure><
GitHub Pagesやライブドアブログ、GoogleのブログサービスのBlogger、Amebaブログなど、はてなブログ以外で使う場合は以下の通り。
<!--GitHub PagesやBloggerなどで使う場合--> <html> <head> <body> <figure> <div class="cocoen"> <img src="<!--左側の画像URL-->"> <img src="<!--右側の画像URL-->"> </div> <figcaption><!--画像キャプションは任意、無くても良い--></figcaption> </figure> </body> </head> </html>
<!--GitHub PagesやBloggerなどで使う場合--> <html> <head> <body> <p> <div class="cocoen"> <img src="<!--左側の画像URL-->"> <img src="<!--右側の画像URL-->"> </div> <figcaption><!--画像キャプションは任意、無くても良い--></figcaption> </p> </body> </head> </html>
大きさの違う画像での比較
片方が小さい画像を用いて、大きさの違う画像を比較する場合は、小さい方の画像に<div style="background: white; display: flex; align-items: center;"></div>
を適用して上下の位置を中央に寄せて小さい画像の背後に大きい画像が写り込まないように背景を白くする事ができる。
<figure> <div class="cocoen"> <div style="background: white; display: flex; align-items: center;"> <!--小さい方の画像に白い背景と上下中央寄せを適用する--> <img src="<!--小さい方の画像URL-->"> </div> <img src="<!--大きい方の画像URL-->"> </div> <figcaption><!--画像キャプションは任意、無くても良い--></figcaption> </figure>
カメラを縦向きにして撮った画像(縦の画像)とカメラを横向きにして撮った画像(横の画像)での比較は、縦の長さや横の長さを調整するなどしたが、縦の画像が横の画像に合わせようと拡大されてしまい、試した限りでは適していない事が分かった。
<!--上手く行かなかったパターン--> <figure> <div class="cocoen"> <div style="background: white; width: 60; height: 100; display: flex; align-items: center;"> <!--縦の画像のサイズ調整--> <img src="<!--縦の画像-->"> </div> <img src="<!--横の画像-->"> </div> <figcaption><!--画像キャプションは任意、無くても良い--></figcaption> </figure>
実装例
【片方が小さい画像を用いて、大きさの違う画像を比較する場合】
【縦の画像と横の画像を用いた比較】
-end-