20201113のHTMLに関する記事は15件です。

【CSS】子要素「僕に逆らう奴は親(要素)でも〇す」

概要

長く生きていると親要素から子要素をはみ出させたい時がくると思います
今回は大きく分けて2通りのやり方ではみ出させてみようと思います

もとの要素はこんな感じ

もとの要素

方法1:ディスプレイ幅に合わせて調整

子要素にvw(viewport width)で、100vwを指定するとウィンドウの幅いっぱいになります

これだけだと、開始位置が親要素に依存するのでズレちゃいます

子要素の開始位置が親要素に依存している

こんな感じに指定すると

.child1 {
  width: 100vw;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
}

子要素の開始位置が親要素に依存しなくなった

コード

oyakoro.html
<div class="parent1">
  parent1
  <div class="child1">child1</div>
</div>
oyakoro.scss
.parent1 {
  text-align: center;
  color: white;
  background-color: #57d1c9;
  width: 50%;
  margin: 12px auto;
  padding: 12px;
  height: 400px;
  > .child1 {
    background-color: #ed5485;
    height: 200px;
    width: 100vw;
    position: relative;
    left: 50%;
    transform: translateX(-50%);
  }
}

方法2:ネガティブマージンを利用

ネガティブマージンとは、marginに、マイナスの数値を指定することです

画像の上に文字を載せたい時などに使われる気がします

方法2-1:calc()を利用

子要素に下記を指定

.child2 {
  margin: 0 calc(((100vw - 100%) / 2) * -1);
}

ネガティブマージンによって、親要素と子要素の幅が相殺される

コード

oyakoro.html
<div class="parent2">
  parent2
  <div class="child2">child2</div>
</div>
oyakoro.scss
.parent2 {
  text-align: center;
  color: white;
  background-color: #0072bb;
  width: 50%;
  margin: 12px auto;
  padding: 12px;
  height: 400px;
  > .child2 {
    height: 200px;
    background-color: #ff4c3b;
    margin: 0 calc(((100vw - 100%) / 2) * -1);
  }
}

方法2-2:力技で幅を広げる

子要素に下記を指定

.child3 {
  margin: 0 -100%;
}

ネガティブマージンで横幅を広げて要素をはみ出させている

コード

oyakoro.html
<div>
  <div class="parent3">
    parent3
    <div class="child3">child3</div>
  </div>
</div>
oyakoro.scss
.parent3 {
  text-align: center;
  color: white;
  background-color: #09194f;
  width: 50%;
  margin: 12px auto;
  padding: 12px;
  height: 400px;
  > .child3 {
    height: 200px;
    background-color: #f9ce00;
    margin: 0 -100%;
  }
}

他に良いやり方あったら教えてくれると嬉しいです

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【初心者でもわかる】文章の最初や最後に、文字や記号を入れる方法(New とか おすすめ!とか)

どうも7noteです。疑似要素を使って、文章の最初や最後に一括で文字を入れる方法。

ニュース記事の一覧や、たとえば物件一覧など、見出しの最後に「New」とか「おすすめ!」みたいな文字を入れるデザインの例。
1つ1つに<span>New</span>みたいにやっていってもいいのですが、修正があったり、自動更新されるページだと毎回手動で処理をするのは大変です。

そんな固定の文字や記号を入れる時は疑似要素が便利。

たとえばこのように、ニュース記事の文章の最後に小さく文字や記号を入れることができます。

完成例

sample.png

最初に入れる方法と、最後に入れる方法の2種類を同時に書いていきます。

ソース

index.html
<ul>
  <li class="new">YouTubeで一時障害 復旧</li>
  <li class="new">PS5発売 抽選倍率100倍超も</li>
  <li class="new">Googleフォト 無料保管制限へ</li>
  <li>独身の日 アリババで7.9兆円</li>
  <li>身代金要求 サイバー攻撃多発</li>
</ul>
style.css
ul,li {
  font-size: 18px;           /* 文字の大きさを指定 */
  list-style: none;          /* デフォルトのリストの「・」を無効化 */
}

ul li::before {
  content: '▼';             /* 最初に入れたい任意の文字を入力 */
}

ul li.new::after {
  content: 'New!';           /* 最後に入れたい任意の文字を入力 */
  font-size: 11px;           /* 文字サイズを11pxに指定 */
  font-weight: bold;         /* 太文字に指定 */
  line-height: 1.3;          /* 行間を指定 */
  display: inline-block;     /* line-heightの背景にも色を入れるため */
  color: #fff;               /* 文字色を白に指定 */
  background: #F00;          /* 背景色を赤に指定 */
  border-radius: 15px;       /* 楕円形にするため角丸 */
  padding: 0 5px;            /* 上下左右に少し余白 */
  margin-left: 10px;         /* これを指定すれば上寄せや下寄せが可能 */
  vertical-align: baseline;  /* これを指定すれば上寄せや下寄せが可能 */
}

解説

まず疑似要素について。
疑似要素は名前の通り、疑似的な要素です。扱いはインライン要素のように扱われるため、beforeなら文章(中のコンテンツ)の前、afterなら文章(中のコンテンツ)の最後に入ります。

検証ツール[F12]でみた疑似要素

f12.png

この特性を利用し、特定のクラスがついている要素にだけ記号やアイコンをつけたり、例のように装飾付きの文字を入れることができます。

まとめ

疑似要素は使いこなせるととても便利なので、ついつい多用しがちなのは私だけですかね?
newアイコンを画像に付けたりなど、いろいろな事ができるので初心者の方は疑似要素の基本的な使い方は抑えておきたいところです。

※疑似要素はCSSなのでSEO対策の文章としては認識されないので注意!SEOに重要な文字は入れないようにしましょう。

おそまつ!

~ Qiitaで毎日投稿中!! ~
【初心者向け】HTML・CSSのちょいテク詰め合わせ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

今日の学び

display:none;とやるよりopacityで0にした方がいいのは知らなかった。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】collection_selectでCSSが適用されない時は、classを指定できてるか確認しよう

はじめに

  • オリジナルアプリ開発で発見したことについて、定着と備忘のためにまとめていきます。

結論

  • CSS書けてるはずなのに変化がないときは、以下を確認してみよう
    • class名が間違っていないか
    • 記述したことが開発ツール上でも表示されているか
  • collection_selectのoptionとHTML属性には {} を付けよう

経緯

やりたいこと

  • collection_selectで作ったセレクトボックスのスタイリングをしたい

作成したコード(誤り)

#erbファイル
<div class="search-field">
  <%= f.label :occupation_id, "職種", class:"search-label" %>
  <%= f.collection_select(:occupation_id, Occupation.all, :id, :name, selected: @search_params[:occupation_id], include_blank: "選択しない", class:"search-occupation") %>
</div>

検索フォームの一部でoccupationモデルから選択出来るようにしています。
collection_selectの具体的な使い方はガイド内をご確認下さい → Railsドキュメント

オプションで下記のものを指定しています。
selected: → 遷移後に@search_paramsの値が選択されるようにしています
include_blank: → 初期状態(選択していない状態)の値を指定しています

次の箇所で問題が発生しました。
3行目のclass:search-occupationに対して下記のCSS記述しましたが、適用されませんでした。

#scssファイル
.search-occupation {
    width: 100%;
    padding: 8px 8px 5px;
    outline: none;
}

開発ツールで確認すると、class:"search-occupation"が指定できていないことが分かりました。(画像3行目)

スクリーンショット 2020-11-13 18.08.41.png

HTMLでclassが指定できていないため、CSSが無効になっている訳ということですね。
対応には下記の記事を参考にさせて頂きました。
ActionView::Helpers::FormOptionsHelper
【Rails】完全理解 formでセレクトボックスをつくるselectの使い方
railsでf.selectにclassを設定する

今回の対応

collection_selectについて調べていく中で、どうやらoptionHTML属性には{}が必要と分かりました。(上述のコードのうち、引数の:nameより後ろの部分)
また、今回のようにoptionが2つある場合は、同じ{}内に記述する必要があります。

  • OK { selected: 〇〇, include_blank: 〇〇}
  • NG { selected: 〇〇}, {include_blank: 〇〇}ArgumentErrorでした

修正したコード

3行目を修正しています

<div class="search-field">
  <%= f.label :occupation_id, "職種", class:"search-label" %>
  <%= f.collection_select(:occupation_id, Occupation.all, :id, :name, {selected: @search_params[:occupation_id], include_blank: "選択しない"}, {class:"search-occupation"}) %>
</div>

おわりに

  • 引数が多いhelperのため、まずは落ち着いてルールを確認したことでスムーズに解決出来ました。
  • また、大元の検索機能はこちらの記事を参考にさせて頂きました。
  • 初学者ゆえ、記事内に誤りがあるかもしれません。ご指摘等ありましたら、お手数ですがコメントを頂けると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【HTML】最も短い湯婆婆【Qiitaで試せます】

はじめに

@Nemesis さんの Javaで湯婆婆を実装してみる@belq さんのPerlのワンライナーで湯婆婆を実装してみるのリスペクト記事です。
上記のPerlの記事が現状最も短い湯婆婆ですがhtmlで頑張った所、もっと短くなりました。

<!doctype html>契約書だよ。そこに名前を書きな。<input id=N><button onclick='P.innerHTML=`フン。${n=N.value}というのかい。贅沢な名だねぇ。今からお前の名前は${m=n[new Date%n.length]}だ。いいかい、${m}だよ。分かったら返事をするんだ、${m}!!`'></button><p id=P>

多分これが一番短いと思います

契約書だよ。そこに名前を書きな。

See the Pen 湯婆婆 by T.D (@td12734) on CodePen.

解説

要件について

湯婆婆の要件は千と千尋の神隠しを見ても分からなかったのでこちらで勝手に決めました。

  • 名前を外部から入力可能
  • 入力された名前からランダムに1文字抜き出した新たな名前を作成する
    • このときに使用する乱数は完全乱数でなくても良い
    • 例外処理の実装は不要
  • 最終的に 契約書だよ。そこに名前を書きな。フン。(名前)というのかい。贅沢な名だねぇ。今からお前の名前は(新しい名前)だ。いいかい、(新しい名前)だよ。分かったら返事をするんだ、(新しい名前)!! の文字を画面に表示する。
    • 改行は任意
    • 上記の文字全てが1つの画面に表示されるべき(だと思われる)

使用テクニック

タグの省略

bodyタグやpタグは閉じタグが無くても動きます。
また、bodyタグの開始タグも特定の状況を除いて省略できます。
buttonタグも後ろに何もなければタグを省略できます。

テンプレートリテラルの使用

+で文字列結合するよりテンプレートリテラルを使う方が非常に短いです。

getElementByIdの省略

getElementByIdで取得したい要素のidと同じ名前の変数を定義していない場合、そのidの名前の変数に取得したい要素が代入されているのでそれを使用します。

変数宣言の簡略化

まず、varを消します。
また、変数の値を最初に使用するタイミングで変数に値を代入します。(${n=N.value}など)

新しい名前の取得

一番工夫した所です。
普通に実装した場合は以下のようになると思います。

m=n.charAt(Math.floor(Math.random()*n.length))

まず、charAtはリストの要素の取得時のように [number] で代用可能です。
次に乱数ですが、 new Date() 、最後のカッコは省略可能なので new Dateを人間が使う場合は乱数として使え、Math.random()より短いのでこちらを使いたいです。
その場合、new Dateは巨大な自然数ですのでnew Dateをn.lengthで割った余りは0から(n.length-1)になります。
また、Math.floorも不要になります。

よって、以下のように新しい名前を取得する処理を大幅に短縮できました。

m=n.charAt(Math.floor(Math.random()*n.length)) //旧、46文字
m=n[new Date%n.length] //新、22文字

おまけ

<!doctype html>について

筆者の環境では省略しても動作しますが、省略したら動かない環境も多いと思われるので今回は消さずに書きました。

湯婆婆の台詞を一度に画面に表示しなくても良い場合

buttonタグの閉じタグなどを省略できるので微妙に短くなります。

<!doctype html><p id=P>契約書だよ。そこに名前を書きな。<input id=N><button onclick='P.innerHTML=`フン。${n=N.value}というのかい。贅沢な名だねぇ。今からお前の名前は${m=n[new Date%n.length]}だ。いいかい、${m}だよ。分かったら返事をするんだ、${m}!!`'>

多分これが実際は一番短いと思います

契約書だよ。そこに名前を書きな。

See the Pen 湯婆婆min by T.D (@td12734) on CodePen.

外部から入力できなくても良い場合

n=>`フン。${n}というのかい。贅沢な名だねぇ。今からお前の名前は${m=n[new Date%n.length]}だ。いいかい、${m}だよ。分かったら返事をするんだ、${m}!!`

たった94文字です。
関数を変数に代入しても96文字で100文字切ってます。
ですが、外部から名前を入力できそうにないので今回はこちらに移動させました。
環境を構築してやればコマンドプロンプトやターミナルから引数を与えて実行できそうな気はします。
なので、

多分これが呼び出せれば一番短いと思います

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【HTML】最も短い湯婆婆【記事内で試せます】

はじめに

@Nemesis さんの Javaで湯婆婆を実装してみる@belq さんのPerlのワンライナーで湯婆婆を実装してみるのリスペクト記事です。
上記のPerlの記事が現状最も短い湯婆婆ですがhtmlで頑張った所、もっと短くなりました。

<!doctype html>契約書だよ。そこに名前を書きな。<input id=N><button onclick='P.innerHTML=`フン。${n=N.value}というのかい。贅沢な名だねぇ。今からお前の名前は${m=n[new Date%n.length]}だ。いいかい、${m}だよ。分かったら返事をするんだ、${m}!!`'></button><p id=P>

多分これが一番短いと思います

契約書だよ。そこに名前を書きな。

See the Pen 湯婆婆 by T.D (@td12734) on CodePen.

解説

要件について

湯婆婆の要件は千と千尋の神隠しを見ても分からなかったのでこちらで勝手に決めました。

  • 名前を外部から入力可能
  • 入力された名前からランダムに1文字抜き出した新たな名前を作成する
    • このときに使用する乱数は完全乱数でなくても良い
    • 例外処理の実装は不要
  • 最終的に 契約書だよ。そこに名前を書きな。フン。(名前)というのかい。贅沢な名だねぇ。今からお前の名前は(新しい名前)だ。いいかい、(新しい名前)だよ。分かったら返事をするんだ、(新しい名前)!! の文字を画面に表示する。
    • 改行は任意
    • 上記の文字全てが1つの画面に表示されるべき(だと思われる)

使用テクニック

タグの省略

bodyタグやpタグは閉じタグが無くても動きます。
また、bodyタグの開始タグも特定の状況を除いて省略できます。
buttonタグも後ろに何もなければタグを省略できます。

テンプレートリテラルの使用

+で文字列結合するよりテンプレートリテラルを使う方が非常に短いです。

getElementByIdの省略

getElementByIdで取得したい要素のidと同じ名前の変数を定義していない場合、そのidの名前の変数に取得したい要素が代入されているのでそれを使用します。

変数宣言の簡略化

まず、varを消します。
また、変数の値を最初に使用するタイミングで変数に値を代入します。(${n=N.value}など)

新しい名前の取得

一番工夫した所です。
普通に実装した場合は以下のようになると思います。

m=n.charAt(Math.floor(Math.random()*n.length))

まず、charAtはリストの要素の取得時のように [number] で代用可能です。
次に乱数ですが、 new Date() 、最後のカッコは省略可能なので new Dateを人間が使う場合は乱数として使え、Math.random()より短いのでこちらを使いたいです。
その場合、new Dateは巨大な自然数ですのでnew Dateをn.lengthで割った余りは0から(n.length-1)になります。
また、Math.floorも不要になります。

よって、以下のように新しい名前を取得する処理を大幅に短縮できました。

m=n.charAt(Math.floor(Math.random()*n.length)) //旧、46文字
m=n[new Date%n.length] //新、22文字

おまけ

<!doctype html>について

筆者の環境では省略しても動作しますが、省略したら動かない環境も多いと思われるので今回は消さずに書きました。

湯婆婆の台詞を一度に画面に表示しなくても良い場合

buttonタグの閉じタグなどを省略できるので微妙に短くなります。

<!doctype html><p id=P>契約書だよ。そこに名前を書きな。<input id=N><button onclick='P.innerHTML=`フン。${n=N.value}というのかい。贅沢な名だねぇ。今からお前の名前は${m=n[new Date%n.length]}だ。いいかい、${m}だよ。分かったら返事をするんだ、${m}!!`'>

多分これが実際は一番短いと思います

契約書だよ。そこに名前を書きな。

See the Pen 湯婆婆min by T.D (@td12734) on CodePen.

外部から入力できなくても良い場合

n=>`フン。${n}というのかい。贅沢な名だねぇ。今からお前の名前は${m=n[new Date%n.length]}だ。いいかい、${m}だよ。分かったら返事をするんだ、${m}!!`

たった94文字です。
関数を変数に代入しても96文字で100文字切ってます。
ですが、外部から名前を入力できそうにないので今回はこちらに移動させました。
環境を構築してやればコマンドプロンプトやターミナルから引数を与えて実行できそうな気はします。
なので、

多分これが呼び出せれば一番短いと思います

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HTMLで最も短い湯婆婆(記事内で試せます)

はじめに

@Nemesis さんの Javaで湯婆婆を実装してみる@belq さんのPerlのワンライナーで湯婆婆を実装してみるのリスペクト記事です。
上記のPerlはワンライナーの湯婆婆ですがhtmlで頑張った所、もっと短くなりました。

<!doctype html>契約書だよ。そこに名前を書きな。<input id=N><button onclick='P.innerHTML=`フン。${n=N.value}というのかい。贅沢な名だねぇ。今からお前の名前は${m=n[new Date%n.length]}だ。いいかい、${m}だよ。分かったら返事をするんだ、${m}!!`'></button><p id=P>

多分これが一番短いと思います

契約書だよ。そこに名前を書きな。

See the Pen 湯婆婆 by T.D (@td12734) on CodePen.

上から記事内でも湯婆婆を試せます。
※コピー用:荻野千尋

解説

要件について

湯婆婆の要件は千と千尋の神隠しを見ても分からなかったのでこちらで勝手に決めました。

  • 名前を外部から入力可能
  • 入力された名前からランダムに1文字抜き出した新たな名前を作成する
    • このときに使用する乱数は完全乱数でなくても良い
    • 例外処理の実装は不要
  • 最終的に 契約書だよ。そこに名前を書きな。フン。(名前)というのかい。贅沢な名だねぇ。今からお前の名前は(新しい名前)だ。いいかい、(新しい名前)だよ。分かったら返事をするんだ、(新しい名前)!! の文字を画面に表示する。
    • 改行は任意
    • 上記の文字全てが1つの画面に表示されるべき(だと思われる)

使用テクニック

タグの省略

bodyタグやpタグは閉じタグが無くても動きます。
また、bodyタグの開始タグも特定の状況を除いて省略できます。
buttonタグも後ろに何もなければタグを省略できます。

テンプレートリテラルの使用

+で文字列結合するよりテンプレートリテラルを使う方が非常に短いです。

getElementByIdの省略

getElementByIdで取得したい要素のidと同じ名前の変数を定義していない場合、そのidの名前の変数に取得したい要素が代入されているのでそれを使用します。

変数宣言の簡略化

まず、varを消します。
また、変数の値を最初に使用するタイミングで変数に値を代入します。(${n=N.value}など)

新しい名前の取得

一番工夫した所です。
普通に実装した場合は以下のようになると思います。

m=n.charAt(Math.floor(Math.random()*n.length))

まず、charAtはリストの要素の取得時のように [number] で代用可能です。
次に乱数ですが、 new Date() 、最後のカッコは省略可能なので new Dateを人間が使う場合は乱数として使え、Math.random()より短いのでこちらを使いたいです。
その場合、new Dateは巨大な自然数ですのでnew Dateをn.lengthで割った余りは0から(n.length-1)になります。
また、Math.floorも不要になります。

よって、以下のように新しい名前を取得する処理を大幅に短縮できました。

m=n.charAt(Math.floor(Math.random()*n.length)) //旧、46文字
m=n[new Date%n.length] //新、22文字

おまけ

<!doctype html>について

筆者の環境では省略しても動作しますが、省略したら動かない環境も多いと思われるので今回は消さずに書きました。

湯婆婆の台詞を一度に画面に表示しなくても良い場合

buttonタグの閉じタグなどを省略できるので微妙に短くなります。

追記
@vf8974 さんの指摘で更に短くなりました。

<!doctype html>契約書だよ。そこに名前を書きな。<input id=N><button onclick='body.innerHTML=`フン。${n=N.value}というのかい。贅沢な名だねぇ。今からお前の名前は${m=n[new Date%n.length]}だ。いいかい、${m}だよ。分かったら返事をするんだ、${m}!!`'>

契約書だよ。そこに名前を書きな。

See the Pen 湯婆婆min by T.D (@td12734) on CodePen.

多分これが実際は一番短いと思います

外部から入力できなくても良い場合

n=>`フン。${n}というのかい。贅沢な名だねぇ。今からお前の名前は${m=n[new Date%n.length]}だ。いいかい、${m}だよ。分かったら返事をするんだ、${m}!!`

たった94文字です。
関数を変数に代入しても96文字で100文字切ってます。
ですが、外部から名前を入力できそうにないので今回はこちらに移動させました。
環境を構築してやればコマンドプロンプトやターミナルから引数を与えて実行できそうな気はします。

追記

コメントで指摘して頂きましたが、以下の記事にあるコードを詰めるとRubyで無慈悲に最短記録が更新されるそうです。(悲しみ)
Rubyで湯婆婆を実装してみる

まだ記事にはなっていないので、
記事になっている湯婆婆では多分これが一番短いと思います

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vimで.phpファイルに書いたhtmlを自動でインデントする方法

" Better indent support for PHP by making it possible to indent HTML sections
" as well.
if exists("b:did_indent")
  finish
endif
" This script pulls in the default indent/php.vim with the :runtime command
" which could re-run this script recursively unless we catch that:
if exists('s:doing_indent_inits')
  finish
endif
let s:doing_indent_inits = 1
runtime! indent/html.vim
unlet b:did_indent
runtime! indent/php.vim
unlet s:doing_indent_inits
function! GetPhpHtmlIndent(lnum)
  if exists('*HtmlIndent')
    let html_ind = HtmlIndent()
  else
    let html_ind = HtmlIndentGet(a:lnum)
  endif
  let php_ind = GetPhpIndent()
  " priority one for php indent script
  if php_ind > -1
    return php_ind
  endif
  if html_ind > -1
    if getline(a:lnum) =~ "^<?" && (0< searchpair('<?', '', '?>', 'nWb')
          \ || 0 < searchpair('<?', '', '?>', 'nW'))
      return -1
    endif
    return html_ind
  endif
  return -1
endfunction
setlocal indentexpr=GetPhpHtmlIndent(v:lnum)
setlocal indentkeys+=<>>

これを~/.vim/indent/php.vimの中に書けばオッケー!

参考:
https://vim.fandom.com/wiki/Better_indent_support_for_php_with_html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsのフラッシュを他のコンテンツを動かさずにフェードアウトさせる

概要

Railsにてエラー等が発生した時、フラッシュを使用し、ページ上部にメッセージを表示させ方法はよく行うことだと思います。
基本的にページを再読み込みするか、別のページへ移動するかしない限り、フラッシュは上部に表示されたままです。
この表示をページを変えなくてもフェードアウトするようプログラムする。

方向性

基本的なflashの設定を行いviewに配置する。class属性を指定し、javascriptでタイマー設定をし、新たなclassを追加し、cssを読み込ませます。

ちなみにjQueryにfadeout()というメソッドがあり、そちらを使うこともできる(記述も簡単である)。
しかし、フェードアウトした後、表示されていたflashの範囲分、ページが上部に急激に上がるため、ユーザー側の立場を考えると困ると考えました。(例:クリックしようとした瞬間、または記事を読んでいる時ページが急激に動く等。)
勉強の意味も込めて、違った方法でフェードアウトさせてみました。

事前準備

controllerでのflashの設定、javascriptの設定等は行われている前提とします。

1.該当項目にclass属性を設定

~html.erb
<body>
  <% if flash.notice %>
    <p class="fadeoutTarget"><%= flash.notice %></p>
  <% end %>
</body>

flash.noticeを囲うpタグにclass属性で"fadeoutTarget"と設定します。もちろん名前は任意で設定可能です。

2.javascriptの設定

app/assets/javascripts/script.js
$(document).on(turbolinks:load, function() {
  /* fadeoutTargetというclassを持った要素を選択 */
  const fadeoutElement = document.querySelector(".fadeoutTarget");
  /* 一定時間経過したらfadeoutというclassを追加する */
  function flashFadeout() {
    setTimeout(function() {
      fadeoutElement.classList.add("fadeout");
    }, 5000);
  }
  /* fadeoutTargetという要素を持ったdocumentがあれば実行 */
  if (fadeoutElement != null) {
    window.onload = flashFadeout();
  }

.querySelector()で任意のclass属性を持った要素を選択します。
この場合、pタグ内のflashの要素を取り出すように設定しています。
setTimeout()で一定時間後、関数を実行するというプログラムになります。
数字の箇所は任意で設定できます。
最後のif文はなくても動くのですが、処理上はfadeoutElementがない時(flash:noticeがない時)、"fadeoutElementがないですよ!"というエラーが出てしまうため、このようにif文で囲っております。

3.cssの設定

app/assets/stylesheets/application.scss
p.fadeoutTarget.fadeout {
  opacity: 0;
  transition: 1s;
}

前項のjavascriptが機能した時、cssが適用されフェードアウトされます。
厳密にはその場で透明になるため、フェードアウト後ページが急激に動いたりすることはありません。

まとめ

要素をフェードアウトさせる方法はたくさんありますので、その都度必要な方法で処理していけるようにしていきたいです。
今回の場合、ページの急激なスクロール移動はありませんが、上部にflash分の余白ができてしまうため、少し見栄えが悪いかもしれません。

個人的には、納得した形で収まったと考えております。またjavascriptの勉強にもなり良い機会でした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

フッターを下部に固定する方法

はじめに

フッターをウィンドウの下部に固定する方法をまとめました。
ページのコンテンツ量が少ない場合でもフッターが下部に固定されるようにします。

方法

まずはHTMLを用意します。

html
<body>
~略~
  <div class="footer-box">
    <span>Copyright © MSY Inc., Ltd. All rights reserved.</span>
  </div>
</body>

次にCSSを用意します。

bodyを画面の大きさにしておきたいのでmin-height: 100vhを設定します。
positionでbodyの子要素であるフッターをbottom: 0で最下部に位置するようにします。
このままだとコンテンツがはみ出てしまうので、フッターの高さ分 padding-bottomを与えます。今回はリセットCSSで指定しているのここでは記述していないが、bodyにbox-sizing: border-box; でpaddingを含めた高さになるようにします。

css
body {
  min-height: 100vh;
  position: relative;
  padding-bottom: 46px;
}

.footer-box {
  width: 100%;
  text-align: center;
  background-color:  #e7e7e7;
  padding: 15px 0;
  position: absolute;
  bottom: 0;
}
.footer-box span {
  font-size: 12px;
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【HTML&JavaScript】canvasでアニメーションを作る方法

プログラミング勉強日記

2020年11月13日
10月の記事でHTMLでcanvasを使うと図形を描ける方法を扱ったが、JavaScriptと組み合わせることでアニメーションを作れると知ったのでその方法をまとめる。

アニメーションを作成する方法

 Canvasはまず、HTML内にCanvasタグを用いてアニメーションを描画する範囲を指定する必要がある。タグを指定して、JavaScriptで動的な動きをかく。

<!--idがCanvasの100×100の大きさのCanvasを作成する -->
<canvas id="Canvas" width="100" height="100"></canvas>

サンプルコード

HTML
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script type="text/javascript" src="sample.js"></script>
    <style>
      #canvas{
        background:#999;
      }
    </style>
  </head>
  <body>
    <!-- Canvasタグでキャンバスを描写する -->
    <canvas id="canvas" width="100" height="100"></canvas>
  </body>
</html>
JavaScript
var can = document.getElementById("canvas");
var ctx = can.getContext("2d");

//アニメーションカウンター
var count = 0;
var timer = setInterval(function(){
  ctx.fillStyl = "#fff"; // 消去時の色
  ctx.clearRect(0,0,300,300);  // 消す
  ctx.fillStyle = "#f00"; // 塗りつぶし色を赤に
  ctx.fillRect(30 + count, 30 + count, 30, 30);
  count++;
  if(count > 200){
    clearInterval(timer);
  }
},100);

参考文献

Canvasを覚える!HTMLでアニメーションを作成する方法【初心者向け】

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js】コンポーネントを使うとうまく表示されない時の解決策

はじめに

Vue.jsを学習している最中にコンポーネントの使い方について躓いたところがあったので、
記録かつ同じ所で躓いた方のためになればと思い、投稿します。

コンポーネントとは?

公式サイト引用

Vue においては、「コンポーネント」は本質的にはあらかじめ定義されたオプションを持つ Vue インスタンスです。

簡単に言い換えると独自のHTMLタグを再利用したいときに使用するものですかね。

使ってみる

jsファイルに"user-item"というコンポーネントを作成。

sample.js
Vue.component('user-item', {
  props: ['user']
  template: '<li>{{ user.name }}</li>'
})

new Vue({
  el: "app-user"
  data: {
    users: [
      {id: 001, name: "Sato"},
      {id: 002, name: "Tanaka"},
      {id: 003, name: "Suzuki"},
    ]
  } 

HTML側で"user-item"タグを使用する。

sample.html
    <div id="app-user">
      <ol>
        <user-item
          v-for="user in users"
          v-bind:user="user"
          v-bind:key="user.id"
        ></user-item>
      </ol>
    </div>

画面での表示はこうなります。
1. Sato
2. Tanaka
3. Suzuki

躓いたポイント

上記のようにV-forを使ってテーブルでも同じことがしたいと思い試したところ、うまくいきませんでした。
試したコード

table.js
Vue.component('user-table', {
  props: ['user'],
  template: '\
    <tr>\
      <td>{{ user.id }}</td>\
      <td>{{ user.name }}</td>\
    </tr>\
    '
})

new Vue({
  el: "#app-table",
  data: {
    users: [
      {id: 001, name: "Sato"},
      {id: 002, name: "Tanaka"},
      {id: 003, name: "Suzuki"},
    ]
  }
});
table.html
    <div id="app-table">
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>NAME</th>
          </tr>
        </thead>
        <tbody>
          <user-table
            v-for="user in users"
            v-bind:user="user"
            v-bind:key="user.id"
          ></user-table>
        </tbody>
      </table>
    </div>

画面での表示
1Sato
2Tanaka
3Suzuki
ID NAME

ヘッダーが一番最後にきてしまっています。

解決策

HTMLにはタグの入れ子にルールがあり、なんでも入れれるわけではありません。
tbodyタグに関してMDN調べると、

許可されている内容 : 0 個以上の tr 要素

つまり、今回のuser-tableタグはHTMLのルールに引っかかっていることが分かりました。

そんな場合にVueではis属性というものが提供されています。
is属性を使用したHTMLコード

table.html(修正後)
    <div id="app-table">
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>NAME</th>
          </tr>
        </thead>
        <tbody>
          <tr is="user-table"
            v-for="user in users"
            v-bind:user="user"
            v-bind:key="user.id"
          ></tr>
        </tbody>
      </table>
    </div>

画面での表示
table.png

うまく表示できました。

まとめ

HTMLの入れ子タグにはルールがあるので、is属性を使って回避しました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【UIデザイン】アイコンの位置による印象の違い

プログラミング勉強日記

2020年11月13日
UIデザインを紐解く。これだけは押さえたいボタンデザインのポイントの記事で、アイコンの位置によってユーザーへ与える印象の違いがあると学びました。
※学習の備忘録として記録しています。

スクリーンショット 2020-11-13 11.46.25.jpg

左にアイコンがある場合

左にアイコンを置いた際は、詳細ページなどへ『入る』イメージを与えます。

そのため、一覧ページから詳細ページなど下の階層に誘導したいときに使用します。

右にアイコンがある場合

左にアイコンを置いた際は、詳細ページなどへ『移動する・外へ出る』イメージを与えます。

そのため、階層の関係ないページへ別ウィンドウで開くページの場合に使用します。

まとめ

アイコンの位置によって、ユーザーへ与える印象が変わると学びました。

これから、LP作成するときなど意識していきたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「画像でゴミ分類!」アプリ作成日誌day5~Bootstrapでフロントエンドを整える2~

はじめに

「画像でゴミ分類!」アプリ作成日誌5日目の今日はBootstrapを使ってフロントエンドを整えていきたいと思います。

<記事一覧>

前回までのあらすじ

前回までの記事では画像認識アプリを実装してDjangoに載せたうえで、フロントエンドを整えるところまでやりました。今回の記事では機能を追加していき、それに合わせてviews.pyやtemplateファイルをいじっていこうと思います。

追加する機能

追加する機能は以下の通りです。

  • サンプル画像による実行
  • サイドメニューの実装
  • フッターの実装

サンプル画像による実行

まず、indexに画像をリンクとして表示できるようにします。

garbage/templates/garbage/index.html
        <h4>既存の画像を利用する</h4>
        <div class="container row">
            <div class="col-md-6 p-3">
                <a href="{% url "garbage:sample1" %}">
                    <img src="./media/images/temp1.jpg" alt="画像1" class="sample-img">
                </a>
            </div>
            <div class="col-md-6 p-3">
                <a href="{% url "garbage:sample2" %}">
                    <img src="./media/images/temp2.jpg" alt="画像2" class="sample-img">
                </a>
            </div>
        </div>

ルーティングとしては

garbage/urls.py
    path("sample1", views.sample1, name="sample1"),
    path("sample2", views.sample2, name="sample2"),

このようにそれぞれ別の関数に渡すようにしています。本来はパラメータとして<a href="{% url "garbage:sample" num:1 %}">として渡してpath("sample/<int:num>", views.sample, name="sample"),と処理すべきだとは思いますが、遷移先のページ上の画像のパスを相対パスで指定しているのでリンクがおかしくなってしまう都合上こうしています。なので、画像の静的フォルダをloadする方法があれば改良したいとは思っています。

そして、viewファイルは以下のようにします。パラメーターで渡せるようになればresultに結合したいですが、とりあえず動くようにしたかったので不格好ですがここに指定する形をとっています。

garbage/views.py
def sample1(request):
    img = "./media/images/temp1.jpg"
    pred = predict(img)

    params = {
        "img":img,
        "pred":pred
    }
    return render(request, "garbage/result.html", params)

サイドメニューの実装

ここはHTMLとCSSで設定をしていきます。
まず、HTMLの書き方は以下です(リンクはリクエストパラメータを省いています)。

garbage/templates/garbage/index.html
        <div class="container row">
            <div class="card col-md-4 py-4 px-0 d-none d-md-block">
                <p role="button" class="mb-2 btn border-dark rounded-0 btn-secondary">外部リンク集</p>
                <a href="https://manage.delight-system.com/threeR/web/bunbetsu" class="btn btn-default border-dark mb-1 rounded-0" role="button" target="_blank" rel="noopener noreferrer">分別検索</a>
                <a href="https://manage.delight-system.com/threeR/web/benri" class="btn btn-default border-dark mb-1 rounded-0" role="button" target="_blank" rel="noopener noreferrer">ごみの分け方・出し方</a>
            </div>

まず、サイドメニューの中に大きく分けて2種類のものを配置しようとしていて、リンクの分類については灰色背景で押せないようになっているボタン、リンクについては点線で枠線を引いたボタンにしています。
p要素については暗めのボタンにしていて、角を尖らせたり色を設定したりするのをBootstrapで指定しています。リンクについては別のタブで開くような設定を書いてあります。

これに対してCSSを以下のように設定します。

garbage/static/garbage/css/style.css
a[role="button"]{
    width: 90%;
    border: dotted 1px;
}

p[role="button"]{
    width: 90%;
}

p[role="button"]:not(:disabled):not(.disabled) {
    cursor: default;
}
p[role="button"]:hover{
    background-color: #6c757d ;
}

width90%や枠線を点線にするのはBootstrapでは設定できないのでCSSで書きます。また、押せないボタンについては、ポインタになったり背景色が変わったりしたら紛らわしいので、Bootstrapで勝手に指定される疑似クラスを上書きするような設定を書いています。(なぜ、こんなことをしてまでBootstrapでボタンにするかというと、リンクのほうでボタンを使うのでそれに合わせて分類についてもボタンにしたほうが見栄えがそろうからです)

フッターの実装

HTMLの書き方は以下です。

garbage/templates/garbage/index.html
        <footer>
            <p id="copyright" class="mb-0">Copyright &copy; 2020 eycjur All Rights Reserved.</p>
        </footer>

これに対してCSSを以下のようにかけます

garbage/static/garbage/css/style.css
#wrapper{
    min-height: 100vh;
    position: relative;
    padding-bottom: 40px;
}

footer{
    position: absolute;
    bottom: 0;
    width: 100%;
}

min-heightを設定することで、footerが浮くことを防止しています。また、padding-bottomで全部スクロールした際にかぶることを防止しています。また、positionを親要素をrelativeにしてfooterをabsoluteにすることで、固定位置で表示します。

以上の3機能を搭載した画面はこんな感じになっています。

ps-3.png
ps-4.png

さいごに

今回は落穂拾い的な感じであまりまとまったことを書けなかったです。逆に個々の機能についてはそれぞれで詳しい記事を書けるような内容であり、需要もそちらのほうがあるとは思うのですが、開発日誌なので自分の作業ペースに合わせて記事を書きたいこともあり、どうすべきかはだいぶ悩んでいます。

次回はサイドバーのスマホ対応についてやろうと思っています!

<記事一覧>

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

神経衰弱の制作

神経衰弱の制作

1〜13までの数字を4つ使った神経衰弱ゲームです。
まずはbody要素内のtable要素にid属性を付与します。

<body onload="init()">
  <table id="table"></table>
</body>

次にグローバル変数に配列cardsとpreCard,flipTimerを定義します。
後で制作したカードをシャッフルできるように、Arrayオブジェクトにprototypeプロパティでshuffle関数を定義します。この関数は配列の一番後ろの要素とランダムに取得した要素の値を交換していく関数です。(一番後ろの要素が繰り返すごとに1ずつ減っていくので全てのカードをシャッフルできる)

  <script>
    let cards = [], prevCard, flipTimer;

    Array.prototype.shuffle = function() {
      for(let i = this.length - 1; i >= 0; i--) {
        let r = Math.floor(Math.random() * (i + 1));
        let s = this[i];
        this[i] = this[r];
        this[r] = s;
      }
      return this;
    }

init関数を定義します。

    function init() {
      for(let i = 1; i < 14; i++)
      {
        cards.push(i);
        cards.push(i);
        cards.push(i);
        cards.push(i);
      }
      cards.shuffle();

      const table = document.getElementById("table");
      for(let i = 0; i < 4; i++) {
        let tr = document.createElement("tr");
        for(let j = 0; j < 13; j++) {
          let td = document.createElement("td");
          let value = cards[i * 13 + j];
          td.value = value;
          td.className = "card";
          td.onclick = flip;
          tr.appendChild(td);
        }
        table.appendChild(tr);
      }
    }

最初の部分で1〜13までの数字を4つ配列cardsに追加します。
その後、配列cardsを先ほど定義したshuffleメソッドでシャッフルします。

    function init() {
      for(let i = 1; i < 14; i++)
      {
        cards.push(i);
        cards.push(i);
        cards.push(i);
        cards.push(i);
      }
      cards.shuffle();

シャッフルした52枚のカードを並べます。
「let value = cards[i * 13 + j]」で52枚のカードを毎回、変数valueに代入します。td要素にはクリックしたときにflip関数が発火するようにします。

      const table = document.getElementById("table");
      for(let i = 0; i < 4; i++) {
        let tr = document.createElement("tr");
        for(let j = 0; j < 13; j++) {
          let td = document.createElement("td");
          let value = cards[i * 13 + j];
          td.value = value;
          td.className = "card";
          td.onclick = flip;
          tr.appendChild(td);
        }
        table.appendChild(tr);
      }
    }

次にflip関数を定義します。

    function flip(e) {
      let src = e.target;
      if(flipTimer || src.textContent != "") {
        return;
      }
      let value = src.value;
      src.className = "";
      src.textContent = value;
      if(prevCard == null) {
        prevCard = src;
        return;
      }

      if(prevCard.value === value) {
        prevCard = null;
        clearTimeout(flipTimer);
      } else {
        flipTimer = setTimeout(function() {
          src.className = "card";
          src.textContent = "";
          prevCard.className = "card";
          prevCard.textContent = "";
          prevCard = null;
          flipTimer = NaN;
        }, 1000);
      }
    }

クリックしたカードのデータを取得できるように、引数に「e」を指定します。
最初のif文では、変数flipTimerに値がある場合とクリックしたカードに数字の表示がある場合に処理を中断するようにしています。
次にクリックしたカードに数字の表示がない場合に自身の値を表示させて、if文で変数prevCardに最初にクリックした1枚目のカードとして値を代入します。

    function flip(e) {
      let src = e.target;
      if(flipTimer || src.textContent != "") {
        return;
      }
      let value = src.value;
      src.className = "";
      src.textContent = value;
      if(prevCard == null) {
        prevCard = src;
        return;
      }

下記ではif文で最初にクリックしたカードと2回目にクリックしたカードが同じ値かどうか判定しています。
同じでなかったときは変数flipTimerにsetTimeoutメソッドを代入します。setTimeoutメソッドは指定した時間が経過した場合に、指定した関数を発火させることができます。ここでは、1000ミリ秒(1秒)経過したら一枚目と二枚目のカードを裏返しに戻します。
一枚目と二枚目が同じかどうかに関係なく、変数prevCardの値を空にします。「flipTimer = NaN」でsetTimeoutが一度発火したら解除されるようにしています。

      if(prevCard.value === value) {
        prevCard = null;
      } else {
        flipTimer = setTimeout(function() {
          src.className = "card";
          src.textContent = "";
          prevCard.className = "card";
          prevCard.textContent = "";
          prevCard = null;
          flipTimer = NaN;
        }, 1000);
      }

下記のコードをコピーしてファイルに貼り付ければ試すことができます。
「.cardセレクタ」のbackground-imageのurl内だけ何か画像を貼り付けてください。

<!DOCTYPE html>

<html>

<head>
  <meta charset="UTF-8">
  <title>b</title>
  <style>
    td {
      width: 50px;
      height: 75px;
      font-size: 30px;
      text-align: center;
      border: 1px solid black;
      border-radius: 5px;
    }
    .card {
      background-image: url(card.png);
      background-size: 50px 75px;
    }
  </style>

  <script>
    let cards = [], prevCard, flipTimer;

    Array.prototype.shuffle = function() {
      for(let i = this.length - 1; i >= 0; i--) {
        let r = Math.floor(Math.random() * (i + 1));
        let s = this[i];
        this[i] = this[r];
        this[r] = s;
      }
      return this;
    }
    function init() {
      for(let i = 1; i < 14; i++)
      {
        cards.push(i);
        cards.push(i);
        cards.push(i);
        cards.push(i);
      }
      cards.shuffle();

      const table = document.getElementById("table");
      for(let i = 0; i < 4; i++) {
        let tr = document.createElement("tr");
        for(let j = 0; j < 13; j++) {
          let td = document.createElement("td");
          let value = cards[i * 13 + j];
          td.value = value;
          td.className = "card";
          td.onclick = flip;
          tr.appendChild(td);
        }
        table.appendChild(tr);
      }
    }

    function flip(e) {
      let src = e.target;
      if(flipTimer || src.textContent != "") {
        return;
      }
      let value = src.value;
      src.className = "";
      src.textContent = value;
      if(prevCard == null) {
        prevCard = src;
        return;
      }

      if(prevCard.value === value) {
        prevCard = null;
      } else {
        flipTimer = setTimeout(function() {
          src.className = "card";
          src.textContent = "";
          prevCard.className = "card";
          prevCard.textContent = "";
          prevCard = null;
          flipTimer = NaN;
        }, 1000);
      }
    }

  </script>
</head>

<body onload="init()">
  <table id="table"></table>
</body>
</html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む