JavascriptとCSSで表示切り替えとか
前回はTabを押した時にページ遷移をして(表示される内容は変わっていませんでしたが)内容を切り替えていました。
今回は、前回作ったものに更にボタン(ラジオボタン)を追加して、非同期でコンテンツの内容を変えてみます。
やったこと
- ボタンを2つ追加して、それぞれを押した時にページの表示内容を非同期で切り替える
- cssでビューポイントを設定して、ウインドウのサイズに合わせて表示内容のサイズを切り替える
はじめに
HTMLにおけるidとclassの関係を勘違いしており、前回のコードで一部同じidを複数箇所で使っているところがありました...。 また、idとclassは一つのタグに対してそれぞれ両方セットすることができるため、javascriptなどで特定の要素にアクセスする場合はidを、表示サイズなど複数要素で共有できるものはclassを使うことで、cssの量を減らすことができそうです。
ページ構成
public以下に、html/0.htmlとhtml/1.htmlというファイルを追加しています。
また、js/jquery-2.1.3.min.jsも追加しています(後述しますが、ネットから取得して利用する形でも問題ありません)。
プロジェクトのルートディレクトリ
Lapp.rb
Lconfig.ru
LGemfile
Lvendor
Lbundle
L...
Lpublic
Ljs
Ljavascript.js
Ljquery-2.1.3.min.js
Lhtml
L0.html
L1.html
Lviews
Llayout.slim
LviewTab.slim
Lcss
Lstylesheet.sass
ページ表示内容の切り替え
Ajaxについては以前もやりましたが、今回は表示したい部分のみを記述したHTMLファイルを作成しておき、それを呼び出して表示する、という処理を行います。
layout.slim
今回は非同期処理のためにjQueryを追加します。public/js/javascript.js同様、layout.htmlから読み込めるようにします。
doctype html
html
head
meta charset="utf-8"
title TabTest
link href="/css/stylesheet.css" rel="stylesheet"
body onload==@updateTabs
main#main
== yield
script src="/js/jquery-2.1.3.min.js"
script src="/js/javascript.js"
viewTab.slim
前回のコードの「section#tab_frame」と同階層に、以下を追加します。
section#tab_frame
〜(省略)〜
section#btn_frame
input#btn_0 type="radio" name="btns" onchange="showContents(0);"
label#btn_label_0.btn_label for="btn_0" ボタン0
input#btn_1 type="radio" name="btns" onchange="showContents(1);"
label#btn_label_1.btn_label for="btn_1" ボタン1
section#contents_frame
- 「section#btn_frame」以下のボタンを切り替えることで、ページの表示内容を切り替えます。
- 読み込んだhtmlは、「section#contents_frame」以下に追加します。
javascript.js
(function() {
〜(省略)〜
this.loadTabs = function(intNewTabNum, intLastRightTabNum){
// ロード時に実行. Tabの表示切り替え、矢印ボタンのEnable/Disable.
intTabNum = intNewTabNum;
intRightTabNum = intLastRightTabNum;
updateTabStyles();
// デフォルトでボタン0のコンテンツが表示されるようにする
document.getElementById("btn_0").checked = true;
showContents(0);
};
〜(省略)〜
this.showContents = function(intNewContentsNum){
$.ajax({
type: 'GET',
url: '/async/' + intNewContentsNum,
dataType: 'html',
success: function(data) {
$('#contents_frame').html(data);
},
error:function() {
alert('Error');
}
});
}
- slimのボタンからだけでなくページロード時に実行する「loadTabs」からも「showContents」を呼んでいるのは、ページ表示時にコンテンツが表示されるようにするためです。
app.rb
〜(省略)〜
get '/async/:name' do
File.open("public/html/" + params[:name].to_s + ".html")
end
end
- 上記では(なんとなく)app.rbでルーティングし、取得したhtmlファイルを返す処理を入れています。
- 「public/html」にアクセスするパスは、app.rbからの場合は「public/html/〜」、public/js/javascript.jsからは「/html/〜」となります。
非同期で呼び出すHTML
基本的には「section#contents_frame」以下に追加する部分だけをHTML形式で記述すればOKです。
ただし、そのままではHTMLは表示されてもCSSは反映されません。
そのため、呼び出すHTML内でスタイルを指定するか、CSSをロードする記述をしてやる必要があります。
0.html
< link href="/css/stylesheet.css" rel="stylesheet" > < div class="zero" id="zero_1" > < div class="zero_inside" id="zero_2" >< /div > < /div >
1.html
< link href="/css/stylesheet.css" rel="stylesheet" > < div class="one" id="one_1" >< /div > < div class="one" id="one_2" >< / div > < div class="one" id="one_3" >< /div >
レスポンシブデザインを取り入れてみる
画面やデバイスのサイズに合わせて、表示したコンテンツの大きさや並びなどを変更する、というレスポンシブデザインにトライしてみました。
やること
今回は後者で作成しました。
stylesheet.sass
$screen_s: 768px
$screen_m_from: 769px
$screen_m_to: 1536px
$screen_l: 1537px
@media only screen and (max-width: $screen_s)
#main
background-color: green
height: 350px
width: 600px
@media only screen and (min-width: $screen_m_from) and (max-width: $screen_m_to)
#main
background-color: red
height: 525px
width: 900px
@media only screen and (min-width: $screen_l)
#main
background-color: blue
height: 700px
width: 1200px
基本的には上記のような感じで、表示したウインドウの横幅の最小値(min-width)や最大値(max-width)を設定して、合致したものを適用します。
- 切り替え自体は自動で行われます。
- 背景色など画面サイズに関係がないものは「@media 〜」の子や孫にならないように書いておけば、すべての条件で適用されます。
- サイズを%で指定している場合は「@media 〜」の条件によらず親に合わせてサイズ変更されるため、これも別途書いておけばOKです。
- 画面サイズを変数として使用できますが、「only screen and (max-width: 768px)」自体を変数とした場合はエラーとなり、使用できませんでした。
というわけでSASSのコードを載せておきます。
stylesheet.sass
$screen_s: 768px
$screen_m_from: 769px
$screen_m_to: 1536px
$screen_l: 1537px
@media only screen and (max-width: $screen_s)
#main
background-color: green
height: 350px
width: 600px
.btn_label
font-size: 10px
height: 100%
width: 20%
border: 1px solid #000
border-radius: 5px
float: left
#zero_1
border-radius: 50%
height: 190px
width: 140px
margin: 40px 0px 0px 230px
overflow: hidden
#zero_2
border-radius: 50%
height: 160px
width: 110px
margin: 15px 0px 0px 15px
#one_1
height: 45px
width: 15px
margin: 40px 0px 0px 282.5px
transform: rotate(45deg)
-moz-transform: rotate(45deg)
-webkit-transform: rotate(45deg)
#one_2
height: 190px
width: 15px
margin: -43.5px 0px 0px 300px
#one_3
height: 15px
width: 76px
margin: 0px 0px 0px 269.5px
@media only screen and (min-width: $screen_m_from) and (max-width: $screen_m_to)
#main
background-color: red
height: 525px
width: 900px
.btn_label
font-size: 15px
height: 100%
width: 20%
border: 1px solid #000
border-radius: 7.5px
float: left
#zero_1
border-radius: 50%
height: 285px
width: 210px
margin: 60px 0px 0px 345px
overflow: hidden
#zero_2
border-radius: 50%
height: 240px
width: 165px
margin: 22.5px 0px 0px 22.5px
#one_1
height: 67.5px
width: 22.5px
margin: 60px 0px 0px 423.75px
transform: rotate(45deg)
-moz-transform: rotate(45deg)
-webkit-transform: rotate(45deg)
#one_2
height: 285px
width: 22.5px
margin: -65.25px 0px 0px 450px
#one_3
height: 22.5px
width: 114px
margin: 0px 0px 0px 404.25px
@media only screen and (min-width: $screen_l)
#main
background-color: blue
height: 700px
width: 1200px
.btn_label
font-size: 20px
height: 100%
width: 20%
border: 1px solid #000
border-radius: 10px
float: left
#zero_1
border-radius: 50%
height: 380px
width: 280px
margin: 80px 0px 0px 460px
overflow: hidden
#zero_2
border-radius: 50%
height: 320px
width: 220px
margin: 30px 0px 0px 30px
#one_1
height: 90px
width: 30px
margin: 80px 0px 0px 565px
transform: rotate(45deg)
-moz-transform: rotate(45deg)
-webkit-transform: rotate(45deg)
#one_2
height: 380px
width: 30px
margin: -87px 0px 0px 600px
#one_3
height: 30px
width: 152px
margin: 0px 0px 0px 539px
#arrow_button_left
left: -999px
position: absolute
top: -999px
#arrow_button_right
left: -999px
position: absolute
top: -999px
input[type="radio"]
top: -999px
left: -999px
position: absolute
#tab_frame
height: 10%
width: 100%
.arrow_label
background-color: #FFF
height: 100%
width: 3.3%
border: 1px solid #000
border-radius: 5%
display: block
float: left
input[type="button"]:disabled + #arrow_label
background-color: #111
height: 100%
width: 20px
border: 1px solid #FFF
border-radius: 5%
display: block
float: left
.tab_label
height: 100%
width: 140px
border: 1px solid #000
border-radius: 5%
float: left
#tab_label_0
background-color: #FFF
#tab_0:checked + #tab_label_0
background-color: #000
#tab_label_1
background-color: #FFF
#tab_1:checked + #tab_label_1
background-color: #000
#tab_label_2
background-color: #FFF
#tab_2:checked + #tab_label_2
background-color: #000
#tab_label_3
background-color: #FFF
#tab_3:checked + #tab_label_3
background-color: #000
#tab_label_4
background-color: #FFF
#tab_4:checked + #tab_label_4
background-color: #000
#btn_frame
height: 5%
width: 100%
overflow: hidden
#btn_label_0
background-color: #386B88
#btn_0:checked + #btn_label_0
background-color: #DEB67E
#btn_label_1
background-color: #386B88
#btn_1:checked + #btn_label_1
background-color: #DEB67E
#contents_frame
background-color: #7AB900
height: 84.8%
width: 100%
overflow: hidden
.zero
background-color: #E7850E
.zero_inside
background-color: #7AB900
.one
background-color: #E7850E
- ちなみに表示されるのは、CSSで表現した0と1の文字です。
- 角丸のborder-radiusは、正円を描く場合は%指定が必要ですが、ボタンなどの角を丸くする場合はpx指定しないと元の四角の形が崩れてしまい、うまく角が丸まりません。
参考
Ajax
Sinatraでのファイルアクセス
レスポンシブデザイン
- デバイスに合わせてCSSを振り分ける「Media Queries」 - Developers.IO
- Sassを使ってレスポンシブウェブデザインにする時に覚えておいた方がいいこと4つ - howtohp
- iPhone/iPad/iPad mini用メディアクエリ一覧 - ENTEREAL/エンタリアル