クリックで画像を拡大するプラグイン(Lightbox)をjQueryなしで自作してみる

Lightboxという単語は死語感が漂っており、今どき需要もなさそうですが…。

というのはさておき、このブログで画像拡大プラグインを導入するにあたり、Photoswipeが候補に挙がったのですが、HTMLの構造の条件が厳しいのと、お手軽感がないのとで、結局自前で実装するに至りました。

デモ

下の写真をクリック/タップしてみてください。モーダルウインドウが開いて画像が拡大表示されます。モーダルウインドウは、ウインドウ内をクリック/タップ、スクロールで閉じることができます。

桜

スイセン

仕様

  • imgタグのsrc属性に指定されている画像を原寸大、もしくは画面いっぱいまで拡大します。HTMLに特別な構造、セレクタは必要ありません。
  • 画像を拡大した際にaltに指定した代替テキストを左上に表示します。
  • アニメーションは全てCSSに押し付けているので、柔軟にカスタマイズできます。
  • IEは全バージョン対応していません(縦横比がおかしくなる or 動かない)。ご了承ください。

コード

CSS

Stylusで書いたものと、コンパイル済みのものを置いておきます。お好きな方をお使いください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#pixel-viewer
display flex
flex-direction column
width 100%
height 100%
background rgba(0, 0, 0, .9)
position fixed
top 0
left 0
z-index 10
animation fadein .2s ease-out both
cursor pointer
user-select none
-webkit-tap-highlight-color transparent
tap-highlight-color transparent

&.fadeout
animation fadeout .2s ease-out both
pointer-events none /* ← IE救済措置(IEでこれがないと画像を閉じた後にページ全体がクリックできなくなります...)*/

& #pixel-viewer__img
animation scaledown .2s ease-out both

#pixel-viewer__alt
width: 100%
height 44px
line-height 44px
padding 0 48px 0 12px
background rgba(0, 0, 0, .95)
color #eee
font-size 14px
text-overflow ellipsis /* スマホなどでaltが横幅をはみ出たときに省略します */
white-space nowrap
overflow hidden

&::before
&::after
content ""
dispaly block
width 24px
height 3px
background #eee
border-radius 4px
position fixed
top 20px
right 12px
z-index 12
&::before
transform rotate(45deg)
&::after
transform rotate(-45deg)

#pixel-viewer__img
display block
margin auto
max-width 100%
max-height calc(100% - 44px)
animation scaleup .2s ease-out both

@keyframes fadein
0%
opacity 0
100%
opacity 1

@keyframes scaleup
0%
transform scale(.95)
100%
transform scale(1)

@keyframes fadeout
0%
opacity 1
100%
opacity 0

@keyframes scaledown
0%
transform scale(1)
100%
transform scale(.95)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#pixel-viewer {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.9);
position: fixed;
top: 0;
left: 0;
z-index: 10;
animation: fadein 0.2s ease-out both;
cursor: pointer;
user-select: none;
-webkit-tap-highlight-color: transparent;
tap-highlight-color: transparent;
}
#pixel-viewer.fadeout {
animation: fadeout 0.2s ease-out both;
pointer-events: none /* ← IE救済措置(IEでこれがないと画像を閉じた後にページ全体がクリックできなくなりますw)*/;
}
#pixel-viewer.fadeout #pixel-viewer__img {
animation: scaledown 0.2s ease-out both;
}
#pixel-viewer__alt {
width: 100%;
height: 44px;
line-height: 44px;
padding: 0 48px 0 12px;
background: rgba(0,0,0,0.95);
color: #eee;
font-size: 14px;
text-overflow: ellipsis /* スマホなどでaltが横幅をはみ出たときに省略します */;
white-space: nowrap;
overflow: hidden;
}
/* 閉じるボタン */
#pixel-viewer__alt::before,
#pixel-viewer__alt::after {
content: "";
dispaly: block;
width: 24px;
height: 3px;
background: #eee;
border-radius: 4px;
position: fixed;
top: 20px;
right: 12px;
z-index: 12;
}
#pixel-viewer__alt::before {
transform: rotate(45deg);
}
#pixel-viewer__alt::after {
transform: rotate(-45deg);
}
#pixel-viewer__img {
display: block;
margin: auto;
max-width: 100%;
max-height: calc(100% - 44px);
animation: scaleup 0.2s ease-out both;
}
@keyframes fadein {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes scaleup {
0% {
transform: scale(0.95);
}
100% {
transform: scale(1);
}
}
@keyframes fadeout {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes scaledown {
0% {
transform: scale(1);
}
100% {
transform: scale(0.95);
}
}

JS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function pixelViewer(element){
const img = document.querySelectorAll(element);

for(let i=0; i < img.length; i++){
img[i].addEventListener('click', open);
}

function open(){
const filter = document.createElement('div');
filter.id = 'pixel-viewer';

const div_alt = document.createElement('div');
div_alt.id = 'pixel-viewer__alt';
div_alt.textContent = this.alt;

const div_img = document.createElement('img');
div_img.id = 'pixel-viewer__img';
div_img.src = this.src;

document.body.appendChild(filter);
filter.appendChild(div_alt);
filter.appendChild(div_img);

filter.addEventListener('click', close, {once: true});
window.addEventListener('scroll', close, {once: true}); // スクロールで閉じたくない場合はこの行を削除

function close(){
filter.className = 'fadeout';
filter.addEventListener("animationend",function(){
filter.remove();
});
}
}
}

1
pixelViewer('p > img');

引数に、記事内のimgタグを全て取得できるようなセレクタを指定してください。querySelectorAllなのでCSSと同じ感覚で書いて大丈夫です。

aタグの中に入った画像は対応していません。子セレクタなどを使って、リンクの中の画像を拾わないようにうまく指定してください。

HTML(記事内)

1
<p><img src="/post/only-css-popup-image/suisen.jpg" alt="スイセン"></p>

上のような感じで、基本的に何もしなくて大丈夫です。

alt表示なし版

左上のalt表示がないバージョンです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function pixelViewer(element){
const img = document.querySelectorAll(element);

for(let i=0; i < img.length; i++){
img[i].addEventListener('click', open);
}

function open(){
const filter = document.createElement('div');
filter.id = 'pixel-viewer';

const div_img = document.createElement('img');
div_img.id = 'pixel-viewer__img';
div_img.src = this.src;

document.body.appendChild(filter);
filter.appendChild(div_img);

filter.addEventListener('click', close, {once: true});
window.addEventListener('scroll', close, {once: true}); // スクロールで閉じたくない場合はこの行を削除

function close(){
filter.className = 'fadeout';
filter.addEventListener("animationend",function(){
filter.remove();
});
}
}
}
pixelViewer('p > img');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#pixel-viewer
display flex
flex-direction column
width 100%
height 100%
background rgba(0,0,0,0.9)
position fixed
top 0
left 0
z-index 10
animation fadein .2s ease-out both
cursor pointer
user-select none
-webkit-tap-highlight-color transparent
tap-highlight-color transparent

&.fadeout
animation fadeout .2s ease-out both
pointer-events none

& #pixel-viewer__img
animation scaledown .2s ease-out both


&::before
&::after
content ""
dispaly block
width 24px
height 3px
background #eee
border-radius 4px
position fixed
top 20px
right 12px
z-index 12
&::before
transform rotate(45deg)
&::after
transform rotate(-45deg)

#pixel-viewer__img
display block
margin auto
max-width 100%
max-height calc(100% - 44px)
animation scaleup .2s ease-out both

@keyframes fadein
0%
opacity 0
100%
opacity 1

@keyframes scaleup
0%
transform scale(.97)
100%
transform scale(1)

@keyframes fadeout
0%
opacity 1
100%
opacity 0

@keyframes scaledown
0%
transform scale(1)
100%
transform scale(.97)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#pixel-viewer {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.9);
position: fixed;
top: 0;
left: 0;
z-index: 10;
animation: fadein 0.2s ease-out both;
cursor: pointer;
user-select: none;
-webkit-tap-highlight-color: transparent;
tap-highlight-color: transparent;
}
#pixel-viewer.fadeout {
animation: fadeout 0.2s ease-out both;
pointer-events: none /* ← IE救済措置(IEでこれがないと画像を閉じた後にページ全体がクリックできなくなります...)*/;
}
#pixel-viewer.fadeout #pixel-viewer__img {
animation: scaledown 0.2s ease-out both;
}
#pixel-viewer::before,
#pixel-viewer::after {
content: "";
dispaly: block;
width: 24px;
height: 3px;
background: #eee;
border-radius: 4px;
position: fixed;
top: 20px;
right: 12px;
z-index: 12;
}
#pixel-viewer::before {
transform: rotate(45deg);
}
#pixel-viewer::after {
transform: rotate(-45deg);
}
#pixel-viewer__img {
display: block;
margin: auto;
max-width: 100%;
max-height: calc(100% - 44px);
animation: scaleup 0.2s ease-out both;
}
@keyframes fadein {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes scaleup {
0% {
transform: scale(0.97);
}
100% {
transform: scale(1);
}
}
@keyframes fadeout {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes scaledown {
0% {
transform: scale(1);
}
100% {
transform: scale(0.97);
}
}

まとめ

素人設計ですが使いたいという方がいらっしゃいましたら、ご自由にお使いください。

このプラグインをJavaScriptを使わずCSSのみで再現するというお遊び記事も書いてるので、実用性はありませんが、よろしければご覧ください。 CSSのみでクリックで画像を拡大する(Lightboxもどき)