画像を重ねる方法(positionとかtopとか)
html5で画像を重ねて表示する方法
毎回力技でやっているので備忘録として
使用するpropertyは主にpositionとz-indexと位置に関するtop/left/bottom/right
基点の指定(position)
- relative, absolute, static, fixedをとる
- 指定しない場合のデフォルトはstatic
static
- positionのデフォルト値
- topとかleft等の位置情報やz-indexを指定しても反映されない
<div> <img src="freedom.jpg" /> </div>
明示的にstaticを指定して位置情報を与えても変わらない
<div style="position: static; top: 150px; left: 100px;"> <img src="freedom.jpg" /> </div>
absolute
- 親ボックスの端を基準にして、指定距離だけ移動した位置に表示
- 親ボックスとはpositionプロパティにstatic以外が指定されている要素のこと
- 何も指定されない場合はwindowの端が基準になる
<div style="position: absolute; top: 150px; left: 100px;"> <img src="freedom.jpg" /> </div>
次にpositionをabsoluteに変更するとtopとleftプロパティが反映され、上端から150px、左端から100pxずれた位置に画像が表示される
ここでずれた位置に画像を一つ追加してみる
<div> <img src="kira.png" /> </div> <div style="position: absolute; top: 150px; left: 100px;"> <img src="freedom.jpg" /> </div>
見事新しい画像が先ほどずらした150pxの空間に配置されました
relative
- 本来そのコンテンツが表示される位置を基準に指定した値だけ移動して表示する
<div style="position: relative; top: 100px; left: 100px;"> <img src="freedom.jpg" /> </div>
単純に1つの画像を表示するだけではabsoluteとほぼ同じ
次にabsoluteとの時と同じくずらした位置に画像を追加します
<div> <img src="kira.png" /> </div> <div style="position: relative; top: 150px; left: 100px;"> <img src="freedom.jpg" /> </div>
すると今度は少し下の位置に表示されてしまいました
これはabsoluteの場合は親ボックス(今回はwindowの端)から指定した分だけ移動した位置に表示されていたのが、relativeの場合は実際に表示されるはずだった位置から指定した分だけ移動しているためです
fixed
- windowの端から指定した距離だけ移動
- そしてスクロールしても移動せずに固定(fix)される
位置の指定(top / bottom/ left / right)
- topは上記で指定した基準からどの程度下にずらすかを示す
- bottom, left, rightは同様に下、左、右からどの程度ずらすかを示す
<div style="position: absolute; top: 50px;"> <img src="freedom.jpg" /> </div>
<div style="position: absolute; bottom: 50px;"> <img src="freedom.jpg" /> </div>
- topとbottom, leftとright両方を指定したい場合、それぞれtopとleftが優先される
<div style="position: absolute; top: 50px; bottom: 50px; left: 50px; right: 50px;"> <img src="freedom.jpg" /> </div>
画像の重ね方
やっと本題の画像の重ね方ですが、上のpositionの位置の指定を使えば簡単にできます
今回はフリーダムの画像の上にキラの写真を重ねます
absoluteの場合
<div> <img src="freedom.jpg" /> </div> <div style="position: absolute; top: 100px; left: 100px;"> <img src="kira.png" /> </div>
親ボックスの左上を基点にして下に100px、右に100px移動したところにキラの顔が表示されました
relativeの場合
上記のpositionを単純にrelativeにすると以下のようになります
これは上で説明したように基点が実際に表示される場所(フリーダムの画像の下)になるためです
このケースでもし画像を重ねあわせたい場合は位置を指定する際に逆にマイナスを指定することで重ねることができます
更に画像を重ねる場合
同じようにpositionと位置を指定していけば何重にも画像を重ねることができます
<div> <img src="freedom.jpg" /> </div> <div style="position: absolute; top: 100px; left: 100px;"> <img src="kira.png" /> </div> <div style="position: absolute; top: 150px; left: 150px;"> <img src="kira2.jpg" /> </div>
重なりの順番(z-index)
今回は順番的に上から『キラ⇒キラ⇒キラの乗ってたやつ』となりましたが、この順番もz-indexで変更することができます
- z-indexの値の大きい要素が上に表示されます
- デフォルトは親要素と同じ値か0です
- positionがstaticの場合は反映されない
なので以下のように記述すれば一番下のフリーダムが1番上に表示されて、他の2枚はその下に隠れます
<div style="position: absolute; z-index: 20;"> <img src="freedom.jpg" /> </div> <div style="position: absolute; top: 100px; left: 100px;"> <img src="kira.png" /> </div> <div style="position: absolute; top: 150px; left: 150px;"> <img src="kira2.jpg" /> </div>
absoluteとrelativeの違い(親要素の高さ)
relativeとabsoluteの違いとしてもう1つあげられるのが、親要素の高さの扱いです。
- relativeの場合はそのまま残る
- absoluteの場合はなくなる
両方staticの場合、親要素に色をつけて見やすくしてみると
<div style="background-color: blue;"> <img src="freedom.jpg" /> </div> <div style="background-color: red;"> <img src="justice.jpg" /> </div>
ここから上の要素をrelative、下をabsoluteにすると
<div style="position: relative; background-color: blue;"> <img src="freedom.jpg" /> </div> <div style="position: absolute; background-color: red;"> <img src="justice.jpg" /> </div>
逆にすると上の要素の高さがなくなり、下のrelativeの要素が基点とする位置がずれて両方の画像が重なってしまいます
わかりやすくabsoluteの方を上になるようにz-indexで調整しています
<div style="position: absolute; background-color: blue; z-index: 2;"> <img src="freedom.jpg" /> </div> <div style="position: relative; background-color: red;"> <img src="justice.jpg" /> </div>
Bootstrapのカルーセル機能の使用方法
carousel
複数の画像が一定間隔でスライドしていく機能のことです
詳しくは下記のリンクをご参照ください。
http://getbootstrap.com/2.3.2/javascript.html#carousel
使い方
<div id="test-carousel" class="carousel slide" data-ride="carousel" data-interval="3000"> <!-- 何枚目かの画像かを表すインディケーター --> <ol class="carousel-indicators"> <li data-target="#test-carousel" data-slide-to="0" class="active"></li> <li data-target="#test-carousel" data-slide-to="1" class=""></li> <li data-target="#test-carousel" data-slide-to="2" class=""></li> </ol> <!-- 実際の画像の表示処理 --> <div class="carousel-inner"> <div class="item active"> <!-- activeをつけたものがページ表示時に表示される --> <img src="./picture1.jpg"> </div> <div class="item"> <img src="./picture2.jpg"> </div> <div class="item"> <img src="./picture3.jpg"> </div> </div> <!-- 前の画像へ戻るための矢印ポインタ --> <a class="left carousel-control" href="#test-carousel" data-slide="prev"> <span class="glyphicon glyphicon-chevron-left"></span> </a> <!-- 次の画像へ進むための矢印ポインタ --> <a class="right carousel-control" href="#test-carousel" data-slide="next"> <span class="glyphicon glyphicon-chevron-right"></span> </a> </div>
data-interval
1行目のdata-intervalが何秒毎に画像をスライドさせるかという設定です。
この場合は3秒です。
bootstrapとjqueryでタブ表示を作成する方法
必要なもの
- bootstrap
- jquery
手順
まずはTabのheaderを作成します。
<!-- Nav tabs --> <div id="tabs"> <!-- Tabs header --> <ul> <li><a id="tabs1" href="#content1">Tab1</a></li> <li><a id="tabs2" href="#content2">Tab2</a></li> </ul> </div>
するとこんな感じのtabが出来ます
次にタブの中のコンテンツを作成します。
<!-- Nav tabs --> <div id="tabs"> <!-- Tabs header --> <ul> <li><a id="tabs1" href="#content1">Tab1</a></li> <li><a id="tabs2" href="#content2">Tab2</a></li> </ul> <!-- Tabs body --> <div id="content1" class="panel"> content1 </div> <div id="content2" class="panel"> content2 </div> </div>
こうするとコンテンツ内の内容が表示されるようになります。
しかしこの段階では全てのコンテンツが全てのタブに表示されています。
次にjs側の設定を行います。
$('[id^=tabs]').click(function(){ $("#tabs li").removeClass("active"); $(this).parent().addClass("active"); $("#tabs .panel").hide(); $(this.hash).fadeIn(); return false; });
これでクリックすると各タブに対応した(hrefで指定した)コンテンツが表示されます。
ページ表示時の設定
しかしこの段階ではクリックする前のページ表示時は全コンテンツが表示されてしまいます。
ページ表示時
なので、最初に表示させるタブを設定します。
$("#tabs1:eq(0)").trigger('click');
- 上記ではtabs1をデフォルトで開くタブに設定しています。
これでページ表示時にもちゃんと一つのタブの内容のみが表示されます
ページ表示時
tablesoterをRailsで使う方法 + FilterとSort機能の使い方
jueryプラグインのtablesorterをRailsで使う方法です。
tablesorterはtableをsortしたりfilteringするjQueryプラグインです。
ソースコード
まずはじめに、tablesorterには本家とforkして他の人が開発しているPageの二つのドキュメントがあります
本家:
http://tablesorter.com/docs/
Fork:
https://mottie.github.io/tablesorter/docs/
今回はForkの方を利用する方法を記載します。
ライブラリのダウンロード
app/assets/javascriptsディレクトリに
をダウンロードして配置します
https://mottie.github.io/tablesorter/docs/#Download
tablesorterの処理を記述
tableの作成
まずは普通にhtmlでtableを作成します。
<table class="tablesorter" border="1"> <thead> <tr> <th>column1</th> <th>column2</th> <th>column3</th> </tr> </thead> <tbody class="table-contents"> <tr> <td>1</td> <td>3</td> <td>2</td> </tr> <tr> <td>foo</td> <td>baz</td> <td>bar</td> </tr> </tbody> </table>
- class属性にtablesorterを指定します
この時点ではこんな感じのtableです。
jsの設定(tablesorter_test.js)
$('table.tablesorter').tablesorter({ });
- 名前はなんでもいいです
application.jsの編集
app/assets/javascripts/application.jsに以下を記述します
//= require jquery-2.1.1.min //= require jquery.tablesorter.combined.js //= require tablesorter_test.js
- 順番は逆にしないようにしましょう
- javascriptsディレクトリ以下全てを読み込む設定にしている場合はそのままでOKです
これだけで一番単純なsort機能は利用できるようになりました
- 各項目でsortすることが出来ます
TableSorterの他の機能の利用
まずデフォルトのTableがこのような状態です
デフォルトでsortさせる
上のままではPage読み込み時にはsortは行われていません。
これを最初から特定のcolumnでsortしておくことが可能です。
sortList: [[${何列目でsortするか}, ${昇順(0)か降順(1)か}]]
- 一番左の列を0とします
例1
$('table.tablesorter').tablesorter({ sortList: [[0,0]], });
- column1(0)で昇順(0)でsortされています
例2
$('table.tablesorter').tablesorter({ sortList: [[2,1]], });
- column3(2)で降順(1)でsortされています
Filter機能
上でjquery.tablesorter.combined.jsを使用している場合は、defaultでfilter機能も利用できます
widgets: ["filter"]
- widgetsとしてfilterウィジェットを利用すると宣言します。
例1
$('table.tablesorter').tablesorter({ widgets: ["filter"], })
- ちょっとずれていますが、filterボックスが各columnに表示され、入力された値でfilteringされうようになりました
filter機能を限定することも可能です
widgets: ["filter"], headers: {${何個目の列か}: { filter: false }},
- widgetsとしてfilterウィジェットを利用すると宣言します。
例2
$('table.tablesorter').tablesorter({ widgets: ["filter"], headers: {0: { filter: false }, 2: { filter: false }}, });
column1(0)とcolumn3(2)のfilter機能は廃止(false)されています
リセットボタン
filterに入力した値をリセットするボタンも簡単に作れます
まずはボタンを作ります
<button class="reset-filter-button">Reset Filter</button>
このボタンにリセット機能をセットします
widgetOptions : { filter_reset : 'button.reset-filter-button', }
例1
$('table.tablesorter').tablesorter({ widgets: ["filter"], widgetOptions : { filter_reset : 'button.reset-filter-button', } });
これで入力値をリセットすることができます。
↓
Reactでinputタグのautofocusを使うには
html
HTML5ではinputタグの中にautofocusと書けば、Pageを表示した際に自動でフォーカスを合わせてくれます。
<input autofocus>-HTML5タグリファレンス
React
しかし、Reactでは下のように普通にinputタグ内にautofocusと書いても反映されません。
var Test = React.createClass( { // 処理とか }, render: function() { return ( <input type='text' autofocus /> }; } );
以下のように書けばReactでもオートフォーカスされます。
. . <input type='text' autoFocus={focus} /> . .
Reference
inputタグで入力中に出てくる青い枠を消す方法
inputタグでテキストボックスに入力している最中に出てくる青い枠線を消す方法です。
input[type="text"]:focus { outline: 0; }
Reactのstate(prop)内で改行文字を使いたい場合
JSX構文
ReactはJSXを採用しているので、構文の中で以下のようにhtmlタグを直接書くようににコーディングできます。
var Test = React.createClass( { // 処理とか }, render: function() { return( <div> {this.state.foobar} </div> ); } );
しかし、このhtmlタグライクなものは、実際のhtmlタグ(DOMノード)ではなく、React側で用意したコンパイラになります。
この<div>は、React.createElement(div)を呼び出しています。
以上のことより、ReactはHTML文字列を生成していないため、XSS対策の必要がありません。
問題
しかし同時に、HTML文字列を直接生成していないということは自分の意図したタグ(改行とか)を入れられないということになります。
<br>に関しては、<br />を使えば改行できますが、8行目のようなReactが管理している値の中に<br>や"\r\n"のような改行文字があっても、それらは単なるStringとして表されるので改行されることはありません。
ここで改行したい<br>さらにここでも改行したい<br>これが最終行
↑こんな風に無改行で表示されてしまします。
対策
ここで改行したい さらにここでも改行したい これが最終行
こんな風にするには一工夫が必要です。
var Test = React.createClass( { this.setState({foobar: 'ここで改行したい<br>さらにここでも改行したい<br>これが最終行'}); }, render: function() { var lines = this.state.foobar.split('<br>').map(function(line) { return (<p>{line}</p>); }); return( <div> {lines} </div> ); } );
- まずstateに入っている文字列を改行文字(<br>や\r\n)で分割します
- その後に、mapを使ってそれぞれを<p>タグで囲みます
- 実際のreturn内ではlinesを呼び出すだけにします
これで<p>タグによって改行される文字列が完成です。
実際は以下のようになります
<p>ここで改行したい</p> <p>さらにここでも改行したい</p> <p>これが最終行</p>
このままだと行間がすごいあいてしまうので、p タグにクラス属性をつけて、cssを設定してやれば行間もなくなります。
React
. . return (<p className='res-line'>{line}</p>); . .
p.res-line { margin: 0; }
※classNameに関しては以下を参照してください
http://portaltan.hatenablog.com/ReactのJSX構文内でclass属性を設定する場合 - 脳汁portal
この問題は色んな人がひっかかってるようで、調べると日本語でも色んなブログが出てきます。
Reactはこういう細かいところの融通がまだきかない気がするので、今後に期待したいです。
(2015/08/11追記)
ちょっと改良
このままだと一つのstateにしか対応してないので、表示するstate毎に処理を書かなければいけない。
ので改良した。
var Test = React.createClass( { getInitialState() { return { foo: '', bar: '' }; }, . . . render: function() { function lines(line) { if (line) { return (<p className='no-margin'>{line}</p>); } else { return (<p className='no-margin'> </p>); } } return ( <div> {this.state.foo.split('<br>').map(lines)} {this.state.bar.split('<br>').map(lines)} </div> ); }