レスポンシブWebデザインとは、パソコンとタブレット、スマートフォンに対応したウェブページを作成する技術である。パソコン専用ページとスマートフォン専用ページのような使い分けがなくなり、1つのページとして作成する。
逆引き:@media、viewport
レスポンシブWebデザインではCSSで@mediaを使用する。CSSの例(g1.css)を示す。
@media (max-width:599px) {
span {
font-weight: normal;
}
}
@media (min-width:600px) and ( max-width:1000px) {
span {
font-weight: bold;
}
}
@media (min-width:1001px) {
span {
font-weight: bold;
font-size: 120%;
}
}
@media (hover: hover) {
span:hover {
background: red;
}
}
これはg1.cssファイルに保存されているものとする。
ここでは@mediaは4種類使用されている。意味は以下のとおりである。
(max-width:599px) 幅が599ピクセル以下である。
(min-width:600px) and ( max-width:1000px) 幅が600ピクセル以上、1000ピクセル以下である。
(min-width:1001px) 幅が1001ピクセル以上である
(hover: hover) マウスなどでホバー可能である。
つぎはHTMLファイル(g1.html)を見てみよう。
<!DOCTYPE html>
<head lang="ja">
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>g1.html</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js"></script>
<link rel="stylesheet" href="g1.css" type="text/css" />
</head><body>
<span>span</span>
</body></html>
これをブラウザで開くとspanというテキストが表示される。幅によって文字サイズと太字が切り替わる。また、spanテキストの上にマウスを持ってくると背景が赤になる。
また、後のサンプルのためvueもインポートしている。viewportについては後述する。
幅が広い時と普通、狭い時に分けて表示を行う例を示す。まず、ファイル名g2.cssのCSSを示す。
.clsWWide { display: none; }
.clsWNormal { display: none; }
.clsWNarrow { display: none; }
@media (max-width:599px) {
.clsWNarrow {
display: block;
}
}
@media (min-width:600px) and ( max-width:1000px) {
.clsWNormal {
display: block;
}
}
@media (min-width:1001px) {
.clsWWide {
display: block;
}
}
次にHTMLファイル(g2.html)を示す。
<!DOCTYPE html>
<head lang="ja">
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>g2.html</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js"></script>
<link rel="stylesheet" href="g2.css" type="text/css" />
</head><body>
<div class="clsWWide">幅はかなーーーーーーりあります。</div>
<div class="clsWNormal">幅は普通くらいです。</div>
<div class="clsWNarrow">狭い</div>
</body></html>
HTMLにはdivタグが3つあるが、表示されるのは幅に対応した1つだけである。
幅が狭い時はメニューをコンテンツの上に重ねたいことがある。一例を示す。前のHTMLサンプルのbodyタグ部分のみ変更する。(g3.html)
</head><body>
<div id="idWrapper">
<div class="clsWWide"><span style="background:lime;">メニュー項目1 メニュー項目2</span></div>
<div class="clsWNormal"><span style="background:lime;">メニュー1 メニュー2</span></div>
<div @click="change" class="clsWNarrow">
<span style="background:green; cursor:pointer;">メニュー</span>
</div>
<div v-show="seen" class="clsWNarrow"
style="background:lime; position:absolute; padding: 0 5px;">
<p>メニュー項目1</p>
<p>メニュー項目2</p>
</div>
メインコンテンツA<br>
メインコンテンツB
</div>
<script>
var vueiWrapper = new Vue({
el: '#idWrapper',
data: { seen: false },
methods: {
change: function(e) {
this.seen = !this.seen;
}
}
})
</script>
</body></html>
幅が500px未満の時は、背景greenのメニュー表示ボタンを表示する。クリックするとメニューの中身の表示/非表示が切り替わる。切り替えのためにvueを使用している。
もし、狭い時のメニュー表示ボタンをページの下に寄せたい場合は「bottom: 0px; position: absolute;」を設定する。(g4.html)
<div @click="change" class="clsWNarrow" style="bottom:0px; position:absolute;">
スマートフォンは画面サイズが小さいが、パソコン用の大きなモニタ向けのウェブページも表示することができる。
以下のコードはスクリーンサイズとブラウザサイズ、解像度レート、解像度を表示するJavaScriptである。
<script>
var s, r;
s = "Screen: " + screen.width + " x " + screen.height+ "pix ";
s = s + "\nWindow: " + window.innerWidth + " x " + window.innerHeight+ "pix ";
r = window.devicePixelRatio;
s = s + "\nRatio: " + r;
s = s + "\nResolution: " + screen.width*r + " x " + screen.height*r + "pix ";
alert(s);
</script>
私のスマートフォンで実行した結果は一例として以下のとおりであった。
Screen: 360 x 640pix
Window: 980 x 1394pix
Ratio: 3
Resolution: 1080 x 1920pix
Screenは画面サイズ、Windowはブラウザの幅と高さ、Resolutionは解像度である。スマートフォンではRatioは3で画面サイズの3倍の解像度があることが分かる。
一方、パソコンで実行した結果は一例として以下のとおりであった。パソコンはRatioは1である。
Screen: 1280 x 1024pix
Window: 1280 x 881pix
Ratio: 1
Resolution 1280 x 1024pix
スマートフォン用にレスポンシブWebデザインで作成したページは小さな画面サイズに対応しているので、Ratioは1で表示したい。このような時にはviewportの設定を行う。以下のような設定である。
<!DOCTYPE html>
<html>
<head>
(略)
<meta name="viewport" content="width=device-width,initial-scale=1">
(略)
</head>
<body>
</body>
</html>
width(横幅)は画面に、initial-scale(初期倍率)は1に合わせている。これでレスポンシブWebデザインを適用することができる。
また、私のAndroidスマートフォンではChromeブラウザで「PC 版サイト」にチェックすると、大きな解像度で表示する。
幅が狭い時はさらにメインコンテンツを上から表示し、メインコンテンツに重ねてメニューボタンを表示する例(g5.html)を示す。
</head><body>
<div id="idWrapper">
<div class="clsWWide"><span style="background:lime;">メニュー項目1 メニュー項目2</span></div>
<div class="clsWNormal"><span style="background:lime;">メニュー1 メニュー2</span></div>
<div @click="change" class="clsWNarrow" style="position:absolute; left:40%; text-align:center;">
<span style="background:green; cursor:pointer; color:white;">メニュー</span>
</div>
<div v-show="seen" class="clsWNarrow"
style="position:absolute; top:40px; background:lime; padding: 5px;">
<p>メニュー項目1</p>
<p>メニュー項目2</p>
</div>
メインコンテンツA<br>
メインコンテンツB
</div>
<script>
var vueiWrapper = new Vue({
el: '#idWrapper',
data: { seen: false },
methods: {
change: function(e) {
this.seen = !this.seen;
}
}
})
</script>
</body></html>
ボタンの位置は「position:absolute; left:40%;」としている。これで一番上の真ん中あたりに表示される。右上にしたければ「left:40%;」を「right:0;」とすればよい。
今までは幅が広い時、間くらい、狭い時の3つを@mediaで指定し、それに合わせてメニュー項目も3つ用意していた。今回は幅が広い時と狭い時の2つにして、メニュー項目は共有する方法を解説する。cssも書き換え、以下のようにする。(g6.css)
/* narrow */
@media (max-width:599px) {
.clsResponsiveMenuButton {
position: absolute;
left: 40%;
text-align: center;
}
.clsResponsiveMenuButton span {
background: green;
cursor: pointer;
color: white;
}
.clsResponsiveMenu {
position: absolute;
top: 40px;
background: lime;
padding: 5px;
}
}
/* wide */
@media (min-width:600px) {
.clsResponsiveMenuButton {
display: none;
}
.clsResponsiveMenu {
display: block !important;
}
.clsResponsiveMenu p {
display: inline;
background: lime;
}
}
スタイル設定はすべてcssファイルで行っている。
次にHTML(g6.html)全体を示す。
<!DOCTYPE html>
<head lang="ja">
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>g6.html</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js"></script>
<link rel="stylesheet" href="g6.css" type="text/css" />
</head><body>
<div id="idWrapper">
<div @click="change" class="clsResponsiveMenuButton">
<span>メニュー</span>
</div>
<div v-show="seen" class="clsResponsiveMenu">
<p>メニュー項目1</p>
<p>メニュー項目2</p>
</div>
メインコンテンツA<br>
メインコンテンツB
</div>
<script>
var vueiWrapper = new Vue({
el: '#idWrapper',
data: { seen: false },
methods: {
change: function(e) {
this.seen = !this.seen;
}
}
})
</script>
</body></html>
各メニュー項目はp要素に入れているが、幅が広い時は「display: inline;」を適用している。これで1行で表示される。また、狭い時のメニューで非表示にしたときに、広い方のメニューが消えないように「display: block !important;」を適用している。