よく使うdisplayプロパティまとめ
displayプロパティとは?
displayプロパティはCSS3において、要素の表示特性を操作するものです。たとえば、ブロック要素をインライン要素に
変更したり、その逆にしたりすることが可能です。(HTML5ではブロック要素やインライン要素といった分類は廃止されましたが説明
を簡単にするため省略します)
よく利用されるのがa要素のブロック化ですね。下記のコードはブロック化する前のリンクです。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>DEMO</title> <link rel="stylesheet" href="style.css"> </head> <body> <nav> <ul> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Works</a></li> <li><a href="#">Links</a></li> </ul> </nav> <body> </html>
body { margin: 0; padding: 0; } nav { background-color: lightgreen; } nav ul { overflow: hidden; list-style: none; } nav li { float: left; width: 100px; border-right: #fff 1px solid; } nav li:first-child { border-left: #fff 1px solid; }
a要素がブロック化されていないと、このようにリンクとして作用するのは文字に触れているあいだだけになります。a要素がデフォルトでは
display: inline;
になっているからです。
この問題を解決するためにa要素にdisplay: block;
を指定してみましょう。CSSに次のように追加します。
nav a { display: block; text-decoration: none; background-color: orange; padding: 10px 0; } nav a:hover { background-color: green; }
a要素がブロック化されていることを証明するためにオレンジ色を施しました。また、文字に触れていなくても、領域全体が
クリック可能になっていることが緑色でわかるはずです。padding
で幅と高さが指定できるようになっているのも
わかりますね。
ちなみに、ここではnav
に直接CSS指定を指定していますが、実際はid
やclass
で指定しましょう。
主要なもの
displayプロパティの種類は結構多いですが、とりあえず以下の4つが基本です。
- block
- float, position等を指定しない限りは配置された要素は自動改行され、上から下へ並ぶ
- width, heightが指定可能
- margin, paddingが指定可能
- vertical-alignプロパティ指定不可
- inline
- br要素で改行されない限り、テキストと同じように横並びになる
- width, heightが指定不可
- 上下marginが指定不可
- vertical-alignプロパティ指定可能
- inline-block
- 上記のinlineと同じく、横並びになる
- width, heightが指定可能
- margin, paddingが指定可能
- vertical-alignプロパティ指定可能
- 親要素のtext-alignでボックスどうしの上下の方向を揃えることが可能
- table-cell
- 要素が一列に横に並ぶ(th, tdのようになる)
- 隣りあう要素の高さは自動的に最も高い要素に揃えられる
- vertical-alignプロパティ指定可能
- 親要素に
display: table;
を指定した上で、その要素にwidth指定を行うと、これを指定 した要素が親要素の幅に合わせて自動で伸縮するようになる
たまに使うもの
- table
- 上記で出てきた
table-cell
とセットで使うことが多い - ブロックレベルボックスとして配置される表(tableをそのままイメージしてもらえれれば良い)
- 上記で出てきた
- list-item
- リスト項目として表示
- ブロックレベルとして配置される
- none
- 要素事態を非表示にしてしまう(ないものとしてしまう)
- 指定された要素の空白領域は確保されず、後続要素が上に詰めて表示される。
最近の主流
display: flex;
と表記することでフレキシブルボックス化することができます。これを利用した
デザインはフレキシブル・ボックス・レイアウトなんて呼ばれるみたいです。複雑なwebサイトを柔軟にレイアウト
できる比較的新しい技術ですが、一部ブラウザでは対応されてないので注意しましょう。
参考
JavaScriptでオブジェクト指向プログラミング
注意(2017.12.30追記)
JavaScriptの進化は早いです。少し前に調べものをしていたら、自分の知っているJSとは別物のような記述の仕方などが出てきて戸惑いました。
この記事では古いクラス実装の手法を紹介していますが、まだこの記事と同じようなスタイルで実装してあるプログラムの保守など、参照の機会はあると思うので少しは役に立つかもしれない、と考えています。
最新のクラス実装の仕方を知りたい方は、記事末尾まで飛んで下さい。軽くですが、最新の手法を載せておきます。
JavaScriptの特徴
JavaScriptは立派なオブジェクト指向言語です。ただし、Javaなんかのオブジェクト指向言語とは
かなり異なる部分があり、オブジェクト指向を知らない初心者がJavaScriptから勉強しはじめると
混乱に陥ります。
まず、JavaScriptにはクラスがありません。かわりにプロトタイプと呼ばれるものが存在します。
ただし、このプロトタイプという言葉自体が混乱を招く結果にもなっていると僕は思います。なので、ここでは便宜上、
プロトタイプのことをクラス、あるいはオブジェクトと呼ぶこととします。
あと、以下のプログラムはGoogle chromeとfirefoxでしかテストしていません。念のため。
空のクラスを定義
まずTestクラスを実装してみます。
var Test = function() { // プロパティ、メソッドなどをこの中に記述 };
これがJavaScriptのクラスです。見てのとおり、厳密にはクラスではありません。関数にクラスとしての役割を与えることで
クラスっぽい挙動をさせるのです。
ちなみにクラスなので変数の最初は大文字です。そうしないと混乱を招くので必ずそうしましょう。
インスタンス化は
var test = new Test();
と記述します。これは他言語と同じような感じですね。
プロパティとメソッドを実装
では上記のクラスにプロパティ、メソッドを書いてみましょう。
var Test = function(name, score) { // プロパティ(Javaだとフィールドにあたる) this.name = name; this.score = score; // メソッド this.getData = function() { return this.name + " : " + this.score; } };
こんな感じになります。
メソッドに注目してください。これはメソッドというよりはプロパティに関数を突っ込んでいるだけ、とも
言えます。実際、JavaScriptではメソッドという概念があるとは言えず、値が関数であるプロパティが
メソッドとしてみなされます。しかし、大体どこでもメソッドと言っている気がしますし、ここでもメソッドで通します。
あと、直観でわかる人もいると思いますがthis
は自分自身(ここではTestクラス自身)です。(正確には、JavaScriptのthisは、
Javaなんかとちょっと違うのですが、ここでは割愛します)
本当に呼び出せるか実際に実行してみます。
var test = new Test("hoge-kun", 75); console.log(test.getData());
hoge-kun : 75
と表示されればOKです。
メソッドの後づけ定義
JavaScriptは一旦インスタンス化させたオブジェクトに対し、新しくメソッドを追加することができます。
言っている意味がわからない人も多いと思いますので具体例を出します。
var Test = function(name, score) { this.name = name; this.score = score; this.getData = function() { return this.name + " : " + this.score; } }; var test = new Test("hoge-kun", 75); // 名前だけ返すgetNameメソッドを追加 test.getName = function() { return this.name; } console.log(test.getName());
ちゃんとhoge-kun
とだけかえってきましたか?
こんなことできていいのかよ、と他言語を使っていた人なら思うでしょう。
これがJavaScriptの柔軟性であり、同時にバグが混入しやすくなる原因でもあります。
たとえば、下記のコードを見てみましょう。
var Test = function(name, score) { this.name = name; this.score = score; this.getData = function() { return this.name + " : " + this.score; } }; // hoge-kunとfuga-chanのTestオブジェクトをインスタンス化 var test_hoge = new Test("hoge-kun", 75); var test_fuga = new Test("fuga-chan", 90); // 変数test_hogeだけに、名前だけ返すgetNameメソッドを追加 test_hoge.getName = function() { return this.name; } console.log(test_hoge.getName()); console.log(test_fuga.getName());
TypeError: test_fuga.getName is not a function
といったような
エラーが返ってきたはずです。そう、メソッドを追加したのは変数test_hogeだけであり、test_fugaには追加
されていないからです。
このようにJavaScriptでは、同じクラスのもとにインスタンス化されたオブジェクトであろうと、それぞれのインスタンスが持つメソッドは
同じとは限らないのです。
メソッドはプロトタイプで宣言しよう
先にコードを出します。
// -- Testクラス(Testオブジェクト) -- // プロパティ(フィールド)はTestクラスをつくったときに var Test = function(name, score) { this.name = name; this.score = score; }; // メソッドはprototypeプロパティへ入れる Test.prototype = { getData : function() { return this.name + " : " + this.score; }, getName : function() { return this.name; } }; // -- Testクラスここまで(実際はここまででファイルを分ける) -- // -- ここからメイン処理 -- var test_hoge = new Test("hoge-kun", 75); var test_fuga = new Test("fuga-chan", 90); console.log(test_hoge.getName()); console.log(test_fuga.getName());
今回はhoge-kun fuga-chan
がともに返ってきます。これがJavaScriptのオブジェクト指向の完成形・・・というわけでは
ないのですが、とりあえずそうしておいてください。少なくとも僕はこう書いています。
この急に出てきた 「prototypeってなに?」 「なんでクラスのなかにメソッド入れてしまわないの?」 と思われる方
もいると思いますが、これを使うといろいろ利点があります。その内の一つが
メモリ消費を抑えることができる
です。
インスタンスは生成するたびに、それぞれのインスタンスのためのメモリを消費します。メソッドをプロトタイプ宣言で追加する前のコードでは、
メソッドをインスタンス化のたびにコピーしていたわけです。
これらのメソッド群をprototypeプロパティで追加すると、オブジェクトをインスタンス化したとき、インスタンスはそれぞれ個別のメソッドを
持つわけではなく、もととなったprototypeオブジェクトを参照することとなります。
図で説明するとこんな感じですね。
毎回メソッドをコピーするわけではなく同じアドレスを見に行っているだけなので、結果としてメモリ節約になるわけです。
ちなみに、上記コードでメソッドをprototypeプロパティへ格納していますが、この手法はオブジェクトのリテラル表現を使っています。
基本形は
var Test = function() { // プロパティ }; Test.prototype.getData() { // 処理 }; Test.prototype.getName() { // 処理 };
のように書きます。しかし、これでは修正箇所が多くなるので、以下のように書くと良いでしょう。
var Test = function() { // プロパティ }; Test.prototype = { getData : function() { // 処理 }, getName : function() { // 処理 } };
読みやすくもなって一石二鳥です。
カプセル化は面倒くさい
PHPの場合
<?php class Test { private $name; private $score; function __construct($name, $score) { $this->name = $name; $this->score = $score; } // $nameは、このメソッドを通しでしか参照できない public function getName() { return $this->name; } // Testクラス内でしか呼び出せないメソッドの処理 private function secretMethod() { // 処理 } }
のようにしてメソッドなどを自分自身のクラス内でしか呼び出せないようにします。$name
や$score
も
パブリックメソッドを通してでしか参照できないようにできます。クラスを設計する際は、通常このようにして
安全性を向上させます。これが俗に言うカプセル化です。
JavaScriptではデフォルトで、すべてのメンバがパブリックになっています。そして、JavaScriptでも
カプセル化を施すことは可能です。
可能なんですが、ちょっと面倒くさいというか、コードが非常に冗長的になるというか・・・。
どうしても仕事で使っていてプライベートメンバにして「危険を取り除きたいんだ!」という方は、ほかの人が良い
方法を書いてくれているはずなので検索してみてください。(投げやり)
静的プロパティ・メソッドの定義
静的プロパティ、静的メソッドとは、インスタンス化せずともオブジェクトから直接呼び出せるプロパティ、メソッド。
グローバル変数、関数を減らすために使用されることが多いです。
以下のように実装します。
/* -- 構文 -- オブジェクト名.プロパティ名 = 値; オブジェクト名.メソッド名 = function() { 処理 }; */ // クラス定義 var StaticTest = function() {}; // 静的プロパティ定義 StaticTest.VERSION = "2.0"; // 静的メソッド定義 StaticTest.returnName = function () { return "STATIC_TEST!"; }; // -- メイン処理 -- console.log(StaticTest.VERSION); console.log(StaticTest.returnName()); var static_test = new StaticTest(); console.log(static_test.returnName()); // エラー
インスタンス経由で静的メソッドを呼び出そうとするとエラーになるはずです。
上記のエラーからわかるように、静的プロパティ及びメソッドを定義する際は、プロトタイプオブジェクトには追加できません。
プロトタイプオブジェクトはインスタンスから直接参照されることを前提としたものだからです。
2017.12.30 追記
ECMAScript 6 からはよりほかの言語に近い形でクラス定義を行えるようになっていました。 結構前からこのように記述できたみたいですね。リサーチ不足でした。
今後はこちらの書き方を見る機会が増えるかもしれません。
<!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> <title>ほかの言語に近い感じで書けるようになった</title> <script> class Student { constructor(name, age) { this.name = name; this.age = age; } info() { console.log(`${this.name} : ${this.age}`); } } const tanaka = new Student('Taro Tanaka', 15); tanaka.info(); </script> </head> <body> </body> </html>
結果
Taro Tanaka : 15
const
は変数を変更できないようにします。変数tanaka
には、新しく数値とかを代入できなくするわけです。(代入するとエラーになる)
今は、変更しないものはconst
で定義してしまうのが主流みたいです。変更する必要がある場合はlet
を使います。
for (var i = 0; i < 10; i++) { } console.log(i); // 数値が出力されてしまう
var
を使っていた場合は漏れちゃってました。
for (let i = 0; i < 10; i++) { } console.log(i); // エラーが出力される
let
を使用した場合には、厳密にスコープ内でおさまってくれます。多言語を使っている人からすれば、まあ、こっちが普通ですから
安心して書けます。
PHPでJSONを扱う
JSONってなに?
JSON(JavaScript Object Notation)は、テキストフォーマットの一種です。シンプルで
開発者が理解しやすい構造をしており、コンピュータにとっては高速で処理しやすいというすぐれもの。
WebAPIなどを使って引っ張ってくる形式のファイルはCSV、XML、JSONのうちどれかですが、
最近の主流はJSON。構造がJavaScriptの連想配列と似ている(というかそのまま?)ので、はじめて
見る人でも理解しやすい。
PHPでJSON処理
下記のようなjsonファイルを用意しました(test.json)。ゲームなんかで使えそうな タイプです。
{ "id" : 24, "name" : "勇者A", "status" : { "hp" : 175, "mp" : 50 }, "item" : { "money" : 25000, "sword" : [ { "name" : "錆びた剣", "atk_point" : 50 }, { "name" : "ライトセーバー", "atk_point" : 350 } ] } }
これをPHPで処理します。具体的には下のコードを参照してください。
<?php $pass = "test.json"; $json = file_get_contents($pass); if (!empty($json)) { $json = mb_convert_encoding($json, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN'); // 連想配列として扱いたい場合は、第2引数にtrueを渡す $obj = json_decode($json); } ?> <!DOCTYPE html> <html lang="ja"> <head> <title>TestJSON</title> <meta charset="utf-8"> </head> <body> <p>ID: <?=$obj->id?></p> <p>名前: <?=$obj->name?></p> <p>HP: <?=$obj->status->hp?></p> <p>MP: <?=$obj->status->mp?></p> <p>所持金: <?=$obj->item->money?></p> <?php foreach ($obj->item->sword as $val): ?> <p>剣の名前: <?=$val->name?></p> <p>剣の攻撃力: <?=$val->atk_point?></p> <?php endforeach; ?> </body> </html>
WebAPIなんかを利用する場合は$passの部分にURLを書きます。今回はなるべくシンプルにした かったのでこのようなコードになりました。コメントアウトにもあるとおり、連想配列として扱いたい場合、 json_decode()の引数にtrueを渡してやります。 僕はオブジェクトとして扱う方が好きなので 今回は使っていません。
$ary = json_decode($json, true);
説明するまでもないですが、これでjsonの内容がすべて出力されます。