20201130のHTMLに関する記事は13件です。

【備忘録】htmlのselectで特定のものを選んだときに追加項目を出し、かつ必須項目に設定する

やりたいこと

formのselect(プルダウンメニュー)で特定のものを選んだら
1.追加項目を出す
2.追加項目に必須項目を設定する

Qiita01.gif

結論

jsを使って入力可否を入れ替える。

index.html
<form method="post" action="〇〇.php" name="〇〇_form">
  <!--もともと表示している項目-->
  <table>
    <tr>
      <th>生産地</th>
      <td><input name="生産地" type="text" id="name" required></td>
    </tr>
    <tr>
      <th>種類</th>
      <td>
        <select name="種類" id="fruitstype" onchange="entryChange();" required>
          <option hidden value="">選択してね</option>
          <option value="ぶどう">ぶどう</option>
          <option value="りんご">りんご</option>
        </select>
      </td>
    </tr>
  </table>
  <!--りんごが選ばれたら表示したい項目-->
  <table id="fruitstypeID">
    <tr>
      <th>品種</th>
      <td><input class="fruitstype-additional-items" size="30" type="text" name="品種" required /></td>
    </tr>
    <tr>
      <th>糖度</th>
      <td>
        <select class="fruitstype-additional-items" name="糖度" required>
          <option hidden value="">選択してね</option>
          <option value="あまい">あまい</option>
          <option value="あまくない">あまくない</option>
        </select>
      </td>
    </tr>
    <div>
      <input type="submit" value="確認" />
    </div>
</form>

script.js
function entryChange() {
  if (document.getElementById('fruitstype')) {
    id = document.getElementById('fruitstype').value;
    //りんごが選ばれたら
    if (id == 'りんご') {
    //追加項目を表示
      document.getElementById('fruitstypeID').style.display = "";
    //追加項目の入力を有効化
      $('.fruitstype-additional-items').removeAttr('disabled');
    //りんごが選ばれなかったら
    } else if (id != 'りんご') {
    //追加項目を非表示
      document.getElementById('fruitstypeID').style.display = "none";
    //追加項目の入力を無効化
      $('.fruitstype-additional-items').attr('disabled', 'disabled');
    }
  }
}
window.onload = entryChange;

考え方

必須項目であるrequiredをつけ外しするのではなく入力可否であるdisabledをつけ外しする。
ぶどうを選んだときでも追加項目が入力可能のままだと確認画面で入力されていないまま表示されてしまうが、disabledを設定することによって確認画面での表示も、必須項目未入力判定も出ない。

他に試した方法

1.PHPの条件分岐(ボタンを押すなどして受け渡しをしなければ発動しないので違う)
2.非同期ajax(その画面のままやるなら非同期型、もっと単純なはず)
3.requitedのつけ外し(思ったままシンプルに)
$('.fruitstype-additional-items').attr('requited');が出来るんじゃないかと思っていたが、出来なかった。

まとめ

「requitedのつけ外し」ができそうで出来なくてかなり時間を使いました。requitedのつけ外しはこんなにシンプルじゃなければ出来るようなので機会があればそっちもやってみたいな…と思います。機会があれば……

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

jQueryに匹敵するフレームワークを作ってやりたいので、中身を作ります。

こんばんは、Sorakimeです。

昨日の投稿を読んでくださると内容が理解できると思うので、先にそちらのほうご一読を推奨します。

昨日の投稿では、骨組みだけを作りましたがあれでは結局なにも動作しません。ですから、簡単に作り方をここに書いておきます。

メソッドというかなんというかを作る方法

昨日の投稿でやりましたね。現在以下のようなソースコードになっていると思います。

shortwrite.js
var _$={
  version: '1.0'
}
window._$=_$;

これは、機能も言った通り連想配列です。ですから、ここからもっと下にキーと値というかここで言うメソッドとその動作する機能の実装をしていばよいわけです。まずは、version: '1.0'の後に,を追加して、改行してから書いていきましょう。
例えば、ここではselectという名前で、querySelectorのそのままの実装を作ってみましょう。ちなみに、この場合には無名関数、function () {}的な書き方かアロー関数、() => {}でもよいです。ここでは、引数は仮にqueryとしておきましょう。そうすれば、以下のようなソースコードが出来上がると思います。

shortwrite.js
var _$={
  version: '1.0',
  select: (query) => {
    return document.querySelector(query);
  }
}
window._$=_$

ちょっと違う、という人もいるかと思います。あと、空白に関しては一行目と4行目以外は無視してくれてよいです。

shortwrite.js
var _$={
  version: '1.0',
  select: function (query) {
    return document.querySelector(query);
  }
}
window._$=_$

これでも違う人はまぁコピペしよう。
基本的な機能はこれで完成です。まぁ、

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <script src="shortwrite.js"></script>
</head>
<body>
  <script>console.log(_$.select())</script>
</body>
</html>

なんて文書かれたらこの場合はどうしようもありませんけどね。対処法としてはif文とかでqueryに何か入ってるかを確認してから動作させるなんてことをすればよいと思います。まぁこんな感じかなぁ。

shortwrite.js
var _$={
  version: '1.0',
  select: (query) => {
    if (query!=null) {
      return document.querySelector(query);
    } else {
      return false;
    }
  }
}
window._$=_$

とまぁこんな感じで機能をどんどん追加していきます。ちなみに何個かメソッドを追加していく方法は知っていますが、メソッドなしの動作方法は知りません。考えておきますが、忘れてる可能性もあります。

ちなみに、Class文とか使うとIEでのサポートができなくなり、少し文も見にくい気がするのでこっちで書いてます。アロー関数使ってる時点でIE無理だけどね。
MDNへGO!
まぁ、最適というだけで使えるので、ファイルサイズ削減にもいいんじゃないかな。昨日さえ思いついたら、全部乗っけていって作ってもいいかも。

ということで、若干雑かもしれないですが終わります。

最後まで読んでくださり、ありがとうございました。

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

30代からのプログラミング勉強 5日目(HTML/CSS入門編)

本日は仕事が休みだったので短時間のコースを一気見しちゃおう!なんて思っていたのですが、MacOSがアプデされておらずこの後できるかなぁといった所です。

と言う訳でまだ時間はありますがキリのいい所まで進んだので投稿していきます。

学習内容

CSS

box-shadow: 0 0 10px rgba(0, 0, 0, .4)

影の設定。X軸、Y軸、影のサイズを指定。rgbaのaで透過度を指定出来る。

太字
font-weight: bold;

boldで太字に指定。数字でも指定可能で、細くする事も可能。

dispray: block;

これについては理解が浅いです…少し調べた限りでは縦に並べる要素を使う事でそのままでは改行されない所で改行させられる…と。

span
<span></span>

divと同じ様にclassを使うなどして区別する上で使用する。ただしdivは改行する性質を持っているので一行内で区別する場合はこちらを使用する。

紐付け
<label for=○○></label>
<input id=○○>

forとidを同値にする事で紐付けがなされる。上記の様に記述するとlabelが付与されているテキストをクリックする事でもテキストボックスの入力が可能になる。

所感

丁度1セクションが終わった所なので、PCが触れない環境でも動画を見返す等して改めて復習し知識の整理を行って行かなければならないと感じる。

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

「初心者向け」JavaScriptで簡単なくじ引きシステムを作る

どうも7noteです。簡単なくじ引きシステムをjavascriptで作ります。

2チームに分けたり、あたりとはずれの本数を決めてくじびきすることができます。

見本
sample.gif

※jQueryを使用しています。jQueryって何?という方はこちら

仕様

・参加メンバーとくじの本数を選択
・スタートボタンを押す。
・あたりの人とはずれの人の2種類に分ける

※くじの本数が足りない時はアラートで警告を出す。

ソース

index.html
<div class="wrapper">
  <div class="area">
    <div id="member">
      <h2>参加メンバーを選ぼう!:</h2>
      <label><input type="checkbox" value="佐藤" checked/> 佐藤</label>
      <label><input type="checkbox" value="田中" checked/> 田中</label>
      <label><input type="checkbox" value="伊藤" checked/> 伊藤</label>
      <label><input type="checkbox" value="鈴木" checked/> 鈴木</label>
      <label><input type="checkbox" value="高橋" checked/> 高橋</label>
    </div>

    <div id="honsuu">
      <h2>くじの本数:</h2>
      あたり:<select name="hit">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
      <option value="4" selected>4</option>
      </select> <!--
-->      はずれ:<select name="miss">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
      <option value="4" selected>4</option>
      </select><br>
    </div>
    <div class="button">
      <input type="button" value="抽選開始" onclick="start();">  <!-- 関数startを実行する。 -->
    </div>
    <div id="result">
      <h3>あたり:</h3>
      <h3>はずれ:</h3>
    </div>
  </div>

</div>
style.css
.wrapper {
  margin: 50px 10%;
  text-align: left;
}

.area {
  width: 80%;
  margin: 0 auto;
}

h2 {
  display: inline-block;
  font-weight: bold;
}

#member {
  margin: 5px auto 20px;
}

#member label {
  display: inline-block;
}

#honsuu {
  margin: 0 auto 20px;
}

.button {
  border-bottom: solid 1px #000;
  padding: 0 0 20px;
  margin: 0 auto 50px
}

#result h3 {
  font-size: 18px;
  font-weight: bold;
}
script.js
var toddayMember = new Array();  // 本日の参加メンバーを入れる配列を新規作成

// 関数start
function start() {
  var theamA = new Array();               // あたりの人たちを入れる配列を新規作成
  var theamB = new Array();               // はずれの…〃
  var hitNum = Number($('select[name="hit"]').val());   // あたりのくじの本数を変数[hitNum]に格納
  var missNum = Number($('select[name="miss"]').val()); // はずれの…〃
  var rand = 0;                           // ランダムの数字 初期値は0

  todayMember = $('input[type="checkbox"]:checked').map(function(){
    return $(this).val();                 // チェックのついたメンバーを配列に格納
  }).get();

  // 人数に対してくじが足りない時にアラートして処理を終了
  if(todayMember.length > hitNum+missNum){
    alert("くじの本数が足りないよ");
    exit;
  }

  // 1人ずつ、あたりもしくははずれを決める
  for(var i = 0; i < todayMember.length; i++ ){
    if(hitNum == 0 && missNum > 0){       // あたりくじがなくなっていて、はずれが余っていればrand=2
      rand = 2;
    }else if(missNum == 0 && hitNum > 0){ // はずれくじがなくなっていて、あたりが余っていればrand=1
      rand = 1;
    }else{                                // どちらでもなければランダムで1か2
      rand = Math.floor( Math.random() * 2 ) + 1;
    }

    if(rand == 1){
      theamA.push(todayMember[i]);        // 1だったらあたりチームの配列に追加
      hitNum += -1;                       // あたりくじを1本減らす
    }else if(rand == 2){
      theamB.push(todayMember[i]);        // 2だったらはずれチームの配列に追加
      missNum += -1;                      // はずれくじを1本減らす
    }
  }
  $("#result h3:first-child").text("あたり:"+theamA); // あたりチームを表示
  $("#result h3:last-child").text("はずれ:"+theamB);  // はずれチームを表示
}

アラートの出方
sample2.gif

解説

分かりやすく分解して書いているので最短の処理や記述ではございませんのであしからず。

  1. ボタンがクリックされ、「start関数」が起動
    • htmlからjavascriptを動かすときは、onclick="start();"のように書くことで、動かすことができます。
  2. あたりチーム、はずれチームそれぞれの配列を作成。また選択されたくじの本数を変数に格納。
    • 新しい配列をつくる時は、new Array()。またselectの要素を取得すると文字列として取得してしまうので、Number()でくくることで数字として変数に格納します。
  3. :checkedの疑似クラスを使って、チェックされた人をtodayMember(変数)に格納
  4. もし「人数 > くじの本数」だった場合、警告文を出して処理を強制終了
    • .lengthで配列にあるデータ数、今回でいうと参加人数の数値を取得できます。
  5. for文を使って1人ずつあたりはずれを抽選する。
    • 最初のif文では、もしすでにどちらかのくじがなくなっていた場合、もう片方のくじを引くように処理を入れています。どちらのくじもまだ残っている場合はランダムの数字を入れます。ランダムはMath.floor( Math.random() * 2 ) + 1とかくことで1もしくは2を取得できます。範囲を広げたいときは2の部分を任意の数時にします。
  6. 後のif文ではランダムで決めた1もしくは2でそれぞれチーム移動とくじを1本減らしています。
    • push()で指定の配列から別の配列に値を追加(複製)します。くじを引いたので-1してのこりのくじの本数を調整します。
  7. text()でhtmlのほうに結果をテキストで出力して完了。

まとめ

プログラミングを始めるきっかけってそれぞれあると思いますが、ゲームなどの面白いものを作りたいって思って始める人が多いように思います。私自身もゲームがすきで自分で作れたらいいなと思いプログラミングの勉強を始めました。

でも始めたての頃は右往左往して何から手を付けたらいいのか分からないものです。
この記事がこれからjavascriptを始めようと思っている人の練習課題的なものになればいいなと思います。
簡単なものから作り始めれば、経験値を重ねていつかは壮大なものも作れるようになるし、もの作りを続けていれば仲間も増えてより様々なもの作りに挑戦できると思います。

おそまつ!

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

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

マイクロソフト公式のWeb開発入門コースに触れてみた

この記事は「【マイスター・ギルド】本物の Advent Calendar 2020」8日目の記事です。

今年11月から入社いたしましたマイスター・ギルド(以下MG)開発部の吉川です。Qiita初投稿となります。

やろうと思ったきっかけ

はてなブックマークの方で話題になっていたことがきっかけです。
400スターくらいついててこれはすごいコースじゃないかと思ってみたら、
コース概要にタイピングゲームやブラウザ拡張機能を作るよ!とあったので
これはやるしかねぇとなったのがきっかけです。MGでは主にフロントエンドを担当させていただいており、JavaScriptを改めて復習したいと思っていたのもあります。

https://github.com/microsoft/Web-Dev-For-Beginners

で、どんなコース?

コースは24レッスンあって、これを12週間かけて取り組みましょうな構成です。
ちなみにオール英語です。

各レッスンには次の内容が入っています。

  • optional sketchnote(オプションのスケッチノート)
  • optional supplemental video(オプションのYoutubeビデオ)
  • pre-lesson warmup quiz(レッスン前のウォームアップクイズ)
  • written lesson(レッスン)
  • for project-based lessons, step-by-step guides on how to build the project-  (プロジェクトの構築方法に関するステップバイステップガイド ※プロジェクトベースのレッスンのみ)
  • knowledge checks(知識チェック)
  • a challenge(チャレンジ)
  • supplemental reading(補足資料)
  • assignment(割りあて)
  • post-lesson quiz(レッスン後のクイズ)

レッスン内容は下記表の通り。

プロジェクト名 教えること 学習目標
1 入門 プログラミングとプログラム売買のツールの紹介 ほとんどのプログラミング言語の背景にある基本的な基盤と、プロの開発者が仕事をするのに役立つソフトウェアについて学習します
2 入門 GitHubの基本(チームでの作業が含む) プロジェクトでGitHubを使用する方法、コードベースで他のユーザーとコミュニケーションする方法
3 入門 アクセシビリティ Webアクセシビリティの基本を学びます
4 JSの基本 JavaScriptデータ型 JavaScriptデータ型の基本
5 JSの基本 関数とメソッド アプリケーションのロジックフローを管理する関数と方法について学習します
6 JSの基本 JSで意思決定 意思決定を使用してコードに条件を作成する方法を学びます
7 JSの基本 配列とループ JavaScriptで配列とループを使用してデータを操作します
8 テラリウム HTMLの実践 レイアウトの構築に重点を置いて、HTMLを構築してオンラインテラリウムを作成します
9 テラリウム CSSの実践 ページをレスポンシブにするなど、CSSの基本に焦点を当てて、オンラインテラリウムのスタイルを設定するCSSを構築します
10 テラリウム JavaScriptクロージャ、DOM操作 クロージャとDOM操作に焦点を当てて、テラリウムをドラッグアンドドロップインターフェイスとして機能させるJavaScriptを構築します
11 タイピングゲーム タイピングゲームを構築する キーボードイベントを使用してJavaScriptアプリのロジックを駆動する方法を学びます
12 グリーンブラウザ拡張機能 ブラウザの操作 ブラウザーのしくみ、ブラウザーの履歴、およびブラウザー拡張機能の最初の要素を足場にする方法を学習します
13 グリーンブラウザ拡張機能 フォームの作成、APIの呼び出し、ローカルストレージへの変数の保存 ブラウザ拡張機能のJavaScript要素を構築して、ローカルストレージに保存されている変数を使用してAPIを呼び出します
14 グリーンブラウザ拡張機能 ブラウザのバックグラウンドプロセス、Webパフォーマンス ブラウザのバックグラウンドプロセスを使用して、拡張機能のアイコンを管理します。Webパフォーマンスといくつかの最適化について学習します
15 宇宙ゲーム JavaScriptを使用したより高度なゲーム開発 ゲームを構築するための準備として、クラスと構成の両方、およびPub / Subパターンを使用した継承について学習します
16 宇宙ゲーム Canvasへの描画 画面に要素を描画するために使用されるCanvasAPIについて学習します
17 宇宙ゲーム 画面上で要素を移動する デカルト座標とCanvasAPIを使用して、要素がどのように動きを得ることができるかを確認します
18 宇宙ゲーム 衝突検出 キーを押すことで要素を衝突させて反応させ、クールダウン機能を提供してゲームのパフォーマンスを確保します
19 宇宙ゲーム スコアを維持する ゲームのステータスとパフォーマンスに基づいて数学計算を実行します
20 宇宙ゲーム ゲームの終了と再会 アセットのクリーンアップや変数値のリセットなど、ゲームの終了と再開について学習します
21 銀行アプリ WebアプリのHTMLテンプレートとルート ルーティングとHTMLテンプレートを使用して、複数ページのWebサイトのアーキテクチャの足場を作成する方法を学習します
22 銀行アプリ WebアプリのHTMLテンプレートとルート ルーティングとHTMLテンプレートを使用して、複数ページのWebサイトのアーキテクチャの足場を作成する方法を学習します
23 銀行アプリ データを取得して使用する方法 アプリにデータが出入りする方法、データを取得、保存、破棄する方法を学習します
24 銀行アプリ 状態管理の概念 アアプリが状態を保持する方法と、プログラムでアプリを管理する方法を学習します

こんな感じで

やったプロジェクト

今回は時間が足りなくてアドカレの一環だし全レッスンやっていると分量が増えすぎてしまうので、グリーンブラウザ拡張機能までやってみました。

  • 入門
  • JSの基本
  • テラリウム
  • タイピングゲーム
  • グリーンブラウザ拡張機能

どんな手順で勉強したの?

筆者はこんな手順で勉強しました。

スケッチノート見る→レッスン前のウォームアップクイズやる→レッスン本文読む
(テラリウムプロジェクト以降のみ)実際にソースコードを動かす→ レッスン後のクイズやる

実際に取り組んだ所感

英語なのでGoogle翻訳とかDeepL翻訳に助けてもらいながら頑張りました。
あと詳しい学習内容はコースページを見ればわかるのでここでは割愛する。1レッスン長くないしね。

入門~JS入門プロジェクト

※以下レッスンのみ日本語化済み(2020/11/28時点)

レッスン1: プログラミングとプログラム売買のツールの紹介

この2プロジェクトは実際に手を動かしてコードを動かすというよりかは、テキストを読んで学習するスタイルとなる。筆者もテキストを読みながらふむふむと学習していた。

入門コースは「プログラミングとは」「プログラミングで使うツール」「GitとGithubの基本的な使い方」「アクセシビリティ」が主なトピック。

なお入門プロジェクトにあるアクセシビリティレッスンに関してはこの手のコースで触れられるのは初めて見たと思う。アクセシビリティについては個人でサイトを作った際にLighthouseというツールを触れた程度なのでこんなツールがあるのか!と感じながら新鮮な気持ちで読んでいました。

JS入門はJavaScriptの「データタイプ」「関数とメソッド」「意思決定」「配列とループ」の4レッスン。レベルはProgateのJavaScriptコースと同じくらい。ES6の初学者は読んでもいいけど、それ以外の人はページ最初のスケッチノートだけ見ておけばいいかなという印象。スケッチノートに学習内容が詰め込まれているし。クラス文に関するレッスンがない点は疑問に感じた。

テラリウム

HTML、CSS、JavaScriptのDOM操作について学習しながら、簡単なドラッグアンドドロップができるテラリウムアプリを作るコース。ここから実際にコードを書いて学習を進めることになる。

完成図はこんな感じです。
image.png

で、植物の絵をドラッグアンドドロップすると、次のように真ん中の瓶の中に植物を設置できるようになります。
image.png

やってみた所感ですが、レッスン中のソースコードを指示に従って写経し完成させる形で作っていくのは楽しい。
ですが、CSSやJavaScriptのプロパティはいくつか補足説明されている一方、特に説明されていない点も少なくなく入門コースにしては説明不足感は否めないように思えた。他サイトのドキュメントで調べてねってことだろうか。
(筆者はpositionプロパティとか位置関係は苦手なのでただ写経する形じゃ辛かった、この辺もっと勉強しないと…)

タイピングゲーム

JavaScriptキーボードイベントを学習しながら、タイピングゲームを作るコース。

完成するとこんな感じでゲームができる。
20201128223158.gif

これはコードが比較的簡単だったのとロジックの説明が順序立てて説明されていたので取り組みやすかったです。ゲームが完成したときはこんな簡単なロジックでエラーも検知できて、クリア時間まで出てくるタイピングゲームができるのかと少し感動していました。

グリーンブラウザ拡張機能

今回筆者が一番楽しみにしていたプロジェクトです。
ここでは「ブラウザについて」「フォームの作成、APIの呼び出し、ローカルストレージの使い方」「Webパフォーマンスの測定・改善」を学びならが、ブラウザ拡張機能を作ることになります。ここで作る拡張機能はC02 Signal APIという外部APIを使用して、地域の二酸化炭素排出量を確認できる拡張機能です。

※ここで作る拡張機能はEdge(おそらくChromium版のみ)、Chrome、Firefoxで動作するとのこと

ここのプロジェクトは拡張機能を作る前の準備がちょっと分かりづらいのでメモを残しておきます。

  1. Node.jsなどでnpmをインストール(多分yarnに置き換えてもいいはず)。
  2. APIを使用するためのAPI Key:ここからメールアドレスを入力するとメールが送られてくるのでそこに書かれているpersonal API token: xxxxxxxxxxxxxxxxxxを見て使ってください。
  3. 地域コード:炭素取得料を調べたい地域のコードをここから取得します。本当は関西の排出量を知りたかったのでJP-KNで調べたかったのですが、取り組んでいた日時だとデータが取得できず、九州を表すJP-KYとしました。
  4. スターターフォルダ:ここのフォルダを今回は使うのでgit cloneなどしてダウンロード。
  5. 4のスターターフォルダをコマンドツールで開き、npm installnpm run buildの順にコマンドを叩く。
  6. 公式はEdgeで紹介されているので、ここではEdgeでの手順を記載。Chromeも拡張機能ページを開いたあとの手順はほぼ同じ(Firefoxは何故か上手く行かなかった)。url欄にedge://extensions/を入力→左下の開発者モードをON→展開して読み込みをクリックし、4のスターターフォルダのdistフォルダを開く。するとMy Carbon Triggerという拡張機能が読み込まれるはずです。
  7. レッスンの指示どおりにコードを書き、終えたあとはnpm run buildするとコードの記載内容が反映されているはずです。

完成図はこんな感じ。調べたい地域の地域コードとAPIKeyを入力し、Submitボタンを押下すると、二酸化炭素使用量と電気の供給における化石燃料(石炭とか石油などのこと)の割合を確認することができる。
image.png


image.png

このプロジェクトを感想した所感としては、axiosを使用したAPI取得を通して、非同期処理とLocalStorage/SessionStorageの説明はわかりやすかった。preventDefaultメソッドはReactを使った開発で出てくるイメージがあって、React専用のものだと思っていたのですが、JavaScript標準のメソッドだったんですね。

最後のパフォーマンスに関するレッスンなのですが、やっていて感じたのが今回の小さめの拡張機能だとパフォーマンス改善は伝わりづらいじゃないかと思った(開発者ツールのパフォーマンスタブの使い方のところは良かったです)。この辺りはWebアプリレッスンでやった方が取り組みやすかったと思う。

今回の記事でやったプロジェクトはここまで。

最後に

本コースをある程度進めた感想としましては、beginnerコースでありながら、「アクセシビリティ」や「LocalStorage/SessionStorage」などこの手のコースでは触れられることは少ない項目もあり、新しく学ぶことも少なくなくやりがいはありました。
ただ、実際にアプリを作るプロジェクトになると、コード写経してくださいと言わんばかりにCSSとかJSプロパティの意味は公式ドキュメントとか外部サイト見てね感はあり、全くのWeb開発初心者がやるのはきついかもしれません。

筆者としては今回できなかった「宇宙アプリ」「銀行アプリ」も忘れないうちに触れていきたい次第です。

本コースは翻訳活動が歓迎されており、Githubのpull requestを開くとすでにいろんな言語の翻訳が進んでいます。ただ、日本語については殆どタッチされておらず残念に思います。ということで時間と気力があれば、本コースの日本語翻訳をいつか私が担当したいなぁと思っている次第です。(まずはJS Primer1周するのが優先ですが…)

あと本コース、docsifyという文書作成ツールをローカルにインストールすると、localhostで読めるみたいですよ。筆者はまだ試せてないので、また別の機会に…

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

非テキストボックスの要素をJavaScriptでテキストボックス化する

概要

spanタグで記述されている要素をJavaScriptでinputタグのテキストボックスに変更する。
口座番号と月末残高の2項目をもつ明細一覧のテーブルがある。月末残高のセルには修正ボタンがあり、修正ボタンを押すとテキストボックス化の処理が実行される。<span>タグで記述されている月末残高の値が、値が保持されたまま<input type="text">に変更される。
なお画面のコードはHTMLだけでなくThymelaefも含む。また、HTMLのid属性が使えない前提がある。
スクリーンショット 2020-11-30 18.21.10.png

用いたコード

example.html
<!DOCTYPE html>
<html xmlns:th ="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>明細一覧</title>
</head>
<body>
  <div align="center">
    <table border="1">
    <tr>
        <th>
        口座番号
        </th>
        <th>
        月末残高
        </th>
    </tr>
    <tr th:each="statement, statementInfo : ${allStatements}">
        <td>
        <span th:text="${statement.accountId}"></span>
        </td>
        <td>
        <form>
          <span th:text="${statement.eomBalance}" class="eomBalance"></span>
          <button type="button" onclick="btn_click()" class="modify" th:name="${statementInfo.index}">修正</button>
        </form>
        </td>
    </tr>
    <tr>
        <td colspan="3">
          <input type="submit" value="送信">
        </td>
    </tr>
    </table>
  </div>
</body>
<script>
function btn_click() {
    var num = event.target.form.querySelector("button[name]").name;
    var eomBalance = document.getElementsByClassName("eomBalance")[num].textContent;
    // inputタグに変更
    document.getElementsByClassName("eomBalance")[num].innerHTML = '<input type=text maxlength="4" th:field="*{eomBalance}" value=' + eomBalance + '>';
}
</script>
</html>

処理

修正ボタンを押下すると、btn_click()が呼ばれる。
押下された修正ボタンがどのフォームか識別するため、buttonタグのname属性から番号を取得する。
name属性はindexを使いth:each処理のインデックスを取得している。

<button type="button" onclick="btn_click()" class="modify" th:name="${statementInfo.index}">修正</button>
var num = event.target.form.querySelector("button[name]").name;

取得した番号を用いて、変更されるセルの月末残高の値をspanタグから取得する。

<span th:text="${statement.eomBalance}" class="eomBalance"></span>
var eomBalance = document.getElementsByClassName("eomBalance")[num].textContent;

月末残高の値を変数eomBalanceに保持したまま、inputタグの文字列を生成する。inputタグの文字列をinnerHTMLから代入する。
※本来はinnerHTMLではなくcreateElementメソッドを用いるべきである。なぜならクロスサイトスクリプティングの脆弱性が発生するからである。

// inputタグに変更
document.getElementsByClassName("eomBalance")[num].innerHTML = '<input type=text maxlength="4" th:field="*{eomBalance}" value=' + eomBalance + '>';
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ウェブアクセシビリティの基礎

アクセシビリティ、ウェブアクセシビリティとは

概要

一般にアクセシビリティとは、アクセスのしやすさを意味します。転じて、製品やサービスの利用しやすさという意味でも使われます。

似た意味をもつ言葉にユーザビリティがありますが、アクセシビリティはユーザビリティより幅広い利用状況、多様な利用者を前提とします。

ウェブのアクセシビリティを言い表す言葉がウェブアクセシビリティです。ウェブコンテンツ、より具体的にはウェブページにある情報や機能の利用しやすさを意味します。

さまざまな利用者が、さまざまなデバイスを使い、さまざまな状況でウェブを使うようになった今、あらゆるウェブコンテンツにとって、ウェブアクセシビリティは必要不可欠な品質と言えます。

以上、https://waic.jp/knowledge/accessibility/ よりコピペ

アクセシビリティとは直訳するとアクセスのしやすさ、サービスの利用しやすさのことを言います。

視覚障害者や聴覚障害者でも使いやすいように、という文脈で使われることが多いですが、あらゆるひと(この言い方を嫌う人もいるかも知れませんが健常者ももちろん含め)が使いやすいことを言います。バリアフリーとの違いはそこですね。バリアフリーは「バリア」があってそれを取り除くの意ですが、アクセシビリティはただ単に「access+-ible+-ty」=「アクセスのしやすさ」という意味の単語です。

WCAG

このウェブアクセシビリティについて基準を定めているところがあります。ウェブサイトに関する多くの仕様を決めているWorld Wide Web Consortium略してW3Cより、Web Content Accessibility Guidelines 2.0略してWCAG 2.0というものが発行されています。対応度に応じてレベルA、AA、AAAは存在し、Aは最低限、AAを目指し、AAAは余裕があればやるぐらいのレベルとされています。

というわけで、具体的にウェブアクセシビリティを大事にするというのはどういうことなのかまとめていきます。
以下はW3C勧告のWCAG(Web Content Accessibility Guidelines) 2.0(日本語訳)の中から

  • 当たり前過ぎて誰でも守るようなもの
  • AAAクラスと、一部AAクラス
  • その他一部の内容

を除いたものを軽くまとめてあります。()内に書かれた番号は、対応するWCAGの章段番号です。

WAI-ARIAについて

WAI-ARIAとは、ウェブアクセシビリティを高めるために定められた属性郡です。詳しくはMDNのWAI-ARIAのページへどうぞ。
role属性とaria-***属性はこのWAI-ARIAで定められたものです。説明はMDNに任せ、この記事では名前に触れるにとどめます。

ウェブアクセシビリティ

非テキストコンテンツ

非テキストコンテンツには原則全てテキストによる代替が必要です。(1.1.1)

画像

img要素にはaltという属性があります。ここには、画像の代わりとして使われるテキストを指定します。
例えば、第70回駒場祭のテーマページは、文字が全て画像になっています。そこで、alt属性には書かれている文章を指定します。1

<img alt="のぞきこむと…第70回駒場祭 七変華" />

他にも、写真を掲載した場合は「〜の様子」などとalt属性を設定すると良いでしょう(一部例外あり、下のよくありそうな間違い参照)。「〜様子」などの名詞ではなく、文章を設定するのも有効な場合もあるでしょう。

alt属性はその名の通り「alternate=代用」となるものです。その画像をその文字列に置き換えて意味が通るかどうかよく確認してください。

よくありそうな間違いを下に記載します。

  • 駒場祭のロゴのalt属性に「第70回駒場祭 ロゴ」とする。
    • alternateとは言えません。ロゴだけならばalt=""にすべきです。ただし、ロゴを紹介している文脈では適切な場合もあります。
  • 三角形に「三角形」とする。
    • やはりalternateとは言えません。次へ移動するボタンなら「次へ移動」など、ただのデザインならalt=""を指定するようにしましょう。
  • 画像の上や下などに画像の説明がすでにテキストにかかれているにも関わらずalt属性に似たような説明を書く。
    • これもalternateとは言えません。テキストのみで画像を説明できている場合はaltは空白を指定しましょう。ただし、aria-labelledby属性を代わりに付けましょう

ちなみにalt未指定とalt=""を指定するのでは意味が異なります。音声読み上げソフトでは、alt=""だと何も読み上げませんが、alt未指定だとファイル名など余計なことを読み上げます。必ずalt=""を指定しましょう。実際にVoiceOverなどでデバッグするのが良いでしょう。

フォーム

フォーム部品を扱う場合は、それが何の入力フォームなのかを「構造的に」はっきり示さないといけません。
構造的にとは

  • label要素を使いフォーム部品とテキストを結びつける。
  • placeholderに説明や入力例を示す。
  • aria-label属性に説明を入れる

等が入ります。(3.3.2)

動画と音声

動画と音声もテキストの代替があることが望まれます(1.1.1、1.3)が、まあ出来たらでいいでしょう。YouTubeをつかえばそんな機能が使えた気がします。

構造化(1.3.1)

構造化要素

p、h1〜h6、ul、li、article、abbr等、「div(span)+文章上の意味」を持つ要素を積極的に使いましょう。

buttonなどを使ってタブを作ったり、やむを得ずdivタグでボタンを作ったりする場合はrole属性を使いましょう。

構造化マークアップ

schema.orgというやつです。検索されるときとかに見やすくなるかもしれません

リンクテキストについて

リンクテキストは、そのリンクだけで内容がわかるようにしましょう。(2.4.4)

【悪い例】 会場へのアクセスはこちら

【良い例】 会場へのアクセスは交通アクセスページ

文字と背景の間にコントラスト比がある

WCAGではコントラスト比は最低限4.5:1あるべきだとし、7:1あることを推奨しています。(1.4.3、1.4.6)

色が唯一の情報識別手段になっていない

色のみで情報の区別をすることはせず、記号の形を変えたり、文字の場合は太字にすることで強調したりするようにしましょう。(1.4.1)

ところで、この世にはCUDとか言うものがありますが、あれ3型2色覚とか1色覚のことはあまり考えてないので、まあCUDを守るのも良いですが、色だけで区別しないことに重点を置くべきでしょう。結局色覚多様性の中でもマイノリティがカバー出来ないので、それに固執するのはあまり好きではありません。

キーボード操作

ウェブサイトで行えることは全てキーボードから行えるようにする(2.1)

まずそもそもa要素のリンクやフォーム部品はTabキーで選択、移動できることを知っておきましょう。
というわけで基本はキーボード操作で全部できるようになっているはずです。

ボタンをdivタグなどで実装するとフォーカス出来なくなってしまいます。基本aタグやbuttonタグなど適した要素で作りましょう。
どうしてもという場合はtabindex="0"という属性を使うとフォーカスできるようになります。が、別途実装が必要になったりするのでやはり控えたほうがいいでしょう。

フォーカス順をちゃんとする(2.4.3)

CSSを使うなどしてソースコードに出てくる順番と視覚的に出てくる順番が違うようにならないようにしましょう。

どうしてもという場合はtabindexという属性に適切な値を入れると順番を制御できます。

その他

フォーカスで大きく表示が切り替わる実装をしない(3.2.1)

動作はクリックなどで起きるようにしましょう。マウスカーソルを乗せるなどで動く実装はあまり良くはありません。


  1. 本当はそもそも画像にしないで文字で配置したほうがいいです。 

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

Youtube Player APIで埋め込んだ複数の動画を1つだけ再生させる制御

Carview Advent Calender 3日目の記事を担当する@yamaberoです。
Qiitaデビューです。緊張します。笑

前提

業務でYoutube動画の埋め込みをすることは、まぁ、よくあることかなと思います。

私も先日ありました。

で、いつものようにYoutube Player APIで動画の埋め込みをしてました。
ただその時は画面内に複数のYoutube動画埋め込みが必要でした。

Youtubeの利用規約

調べてみると埋め込みしたYoutubeって同じページ内に1つまでしか動画を再生してはいけないらしんですよ。->利用規約III - C -1(英語)
どっちかっていうとIII - C - 1に書かれてるミニマムリクワイアメントの方が良いか。

A page or screen must not have more than one YouTube player that automatically plays content simultaneously.
1つのページまたは画面に、コンテンツを自動的に同時に再生する複数のYouTubeプレーヤーを含めることはできません。(google翻訳)

自動再生でかつ同時再生を複数のプレーヤーでしてはいけないって感じですが、手動再生も念の為同時には再生できない仕組みにしておいた方が良さそうです。

ソースコード

というわけで以下の様な感じのJavaScriptにしました。
参考にしたのは https://www.neko-it.com/blog/4536.html です。
まるっと一緒にするわけには行かないので、ちょいちょい変更はしてます。

htmlサンプル
<div class="wrapper">
  <div class="movie--node">
    <div id="movie01"></div>
  </div>

  <div class="movie--node">
    <div id="movie02"></div>
  </div>

  <div class="movie--node">
    <div id="movie03"></div>
  </div>
</div>

htmlは、まぁ、テキトーです。
どうせ埋め込みするだけなので。

Javascriptサンプル
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

// 各プレーヤーの格納配列準備
const ytPlayer = [];

// Youtube再生判定用
let ytPlaying, ytStop, ytPlay;

// 各動画情報
const ytData = [
  {
    id: "duFiiDPiwjc", // youtube動画のID
    area: 'movie01', // youtube動画を埋め込む場所
    pWidth: '560', // 動画の幅
    pHeight: '315' // 動画の高さ設定用
  },
  {
    id: "0XmIVbmeZ-I", // youtube動画のID
    area: 'movie02', // youtube動画を埋め込む場所
    pWidth: '560', // 動画の幅
    pHeight: '315' // 動画の高さ設定用
  },
  {
    id: "GBdDJHknrBQ", // youtube動画のID
    area: 'movie03', // youtube動画を埋め込む場所
    pWidth: '560', // 動画の幅
    pHeight: '315' // 動画の高さ設定用
  }
];

// 各プレーヤーの埋め込み
function onYouTubeIframeAPIReady() {
  for (let n = 0; n < ytData.length; n++) {
    ytPlayer[n] = new YT.Player(ytData[n]['area'], {
      width: ytData[n]['pWidth'],
      height: ytData[n]['pHeight'],
      videoId: ytData[n]['id'],
      playerVars: {
        rel: 0,
        playsinline: 1
      },
      events: {
        onReady: function(evt) { // ここに動画再生の準備ができた時に実行したいscriptを記述
        },
        onStateChange: function(evt) { // ここに動画のステータスが変わった時に実行したいscriptを記述
          /* 複数再生させない制御 */
          // 各プレーヤーの状態確認
          let thisState = ytPlayer[n].getPlayerState();

          if (thisState === 1 && typeof ytPlaying === 'undefined') { // 初回再生時
            ytPlaying = n;
          } else if (thisState === 1 && ytPlaying !== n) { // 他が再生されてる時
            ytStop = ytPlaying;
            ytPlay = n;
          }

          // 同時再生があった場合、元々再生していた方を停止する
          if (typeof ytStop !== 'undefined' && ytStop !== '') {
            ytPlayer[ytStop].pauseVideo();
            ytStop = '';
          }

          // 現在再生中のプレーヤー番号を保存しておく
          if (typeof ytPlay !== 'undefined' && ytPlay !== '') {
            ytPlaying = ytPlay;
            ytPlay = '';
          }
        }
      }
    });
  }
}

JavaScriptがキモなので、分割してちょっと説明します。

各プレーヤーの状態確認

各プレーヤーの状態確認
let thisState = ytPlayer[n].getPlayerState();

Youtube Player APIの説明ページにあるイベントの中に「onStateChange」の説明があります。

このイベントは、プレーヤーの状態が変わると起動します。 API がイベント リスナー関数に渡すイベント オブジェクトの data プロパティにより、プレーヤーの新しい状態に対応する整数が指定されます。 有効な値は次のとおりです。
-1(未開始)
0(終了)
1(再生中)
2(停止)
3(バッファリング中)
5(頭出し済み)

なので埋め込まれている動画の状態を「getPlayerState()」で取得します。
それをthisStateへと格納します。
再生中であれば「1」になるので、以下の様にして再生してることをif文に記載してます。

再生時
if (thisState === 1 && typeof ytPlaying === 'undefined') { // 初回再生時
  ytPlaying = n;
} else if (thisState === 1 && ytPlaying !== n) { // 他が再生されてる時
  ytStop = ytPlaying;
  ytPlay = n;
}

あとは状態を判別して、動画再生ボタンが押された時に

  • 再生ボタンを押した動画を再生開始
  • もともと再生されてた動画ストップと番号の保存

という処理を行なっています。

再生中の停止と再生中の動画の保存
// 同時再生があった場合、元々再生していた方を停止する
if (typeof ytStop !== 'undefined' && ytStop !== '') {
  ytPlayer[ytStop].pauseVideo();
  ytStop = '';
}

// 現在再生中のプレーヤー番号を保存しておく
if (typeof ytPlay !== 'undefined' && ytPlay !== '') {
  ytPlaying = ytPlay;
  ytPlay = '';
}

参考にしたブログ記事と明確に変えたところは厳密等価演算子に変えたってとこですかね。

実行結果

最後にCodePenで上記コードを記載して実行したものを入れておきます。

See the Pen youtube multiple embed by yamabero (@yamabero) on CodePen.

参考

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

jQueryに匹敵するフレームワークを作ってやる (それはさすがに無理)

こんにちは。Sorakimeです。

タイトルにありますが、jQueryに匹敵するくらいのフレームワークを自作してみたいと思います。ただ、さすがにそれは難しいので、とりあえず実用的なフレームワークをjQueryを一切使ったことのないわたくしSorakimeが作ってみたいと思います。

目次

1. 開発に至った経緯
2. 仕組みというか・・・設計?
3. 外からアクセスしてみよう
(リンクは適当に切り貼りしただけです)


開発に至った経緯

ずっと生のJavaScriptを書いてきました。ところが、Electronやその他のWeb技術を用いてアプリケーションを開発することがかなり多くなったと思ったので、効率化を図ったほうが良いと思ったからです。しかし、自分は脱jQuery派人間、というか既存のものの再利用よりできることなら何でも自作しようとする人間なので、自分で自作しました。自作しています。まだ開発中です。また、自分で作ったほうが仕組みや問題点、ソースコードなどがわかりやすい・見やすいと思ったからです。


仕組みというか・・・設計?

ソースコードの作り、というか。なんと説明すればよいのかわかりませんが、中身についてこのセクションでは書きます。
ですが、詳細が必要なのでここに示しておきます。ただし、かなり基本的な情報です。

項目 内容
フレームワーク名 ShortWrite.js
バージョン 自称1.0
言語 JavaScript(ネイティブ)
開発者 Sorakime
メインの変数名 _$
エイリアス _$

まず、骨組みだけのソースコードを以下に表示します。これを実行しても、合うソースコードを書いたとしても、ユーザに直接見える形では動作しません。

shortwrite.js
var _$={}
window._$=_$;

はい、かなり単純です。まず一行目で_$というオブジェクト、というかハッシュとか連想配列とか言われてるやつを作ります。その中に機能を書いていきます。で、その下の二行目に、ほかのJavaScriptファイルでもこのフレームワークを実行できるようにするなんか呪文みたいなやつがあります。
そんな形になっています。

追記(2020年11月30日):
最後のwindow._$ですが、もし一番後ろでこのフレームワークを読み込んでいる場合に正常に動作させるために書いております。動作確認したところ、正常に動作しなかったので一応ここに書かせていただいております。なお、一番上の<head>要素内の書かれている分にはwindow._$=_$という文を書かれていなくても動作させることは可能でした。

外からアクセスしてみよう

ほかのファイルからこのshortwrite.jsファイルを読み込んで、実際に使えるようにします。
といっても、さっきのwindow._$=_$;で宣言で来ているのは事実ですけどね。
まずは、さっき作った_$オブジェクトの中身を書きましょう。ここでは、versionというものを用意しました。こういったソースコードになります。

shortwrite.js
var _$={
  version: '1.0'
}
window._$=_$;

というものが出来上がります。では、HTMLファイルからこのフレームワークにアクセスしてみましょう。
では、以下の内容でさっき作ったshortwrite.jsファイルがある階層にhtmlファイルを作ってみましょう。名前は何でもOKです。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>test</title>
    <script src="shortwrite.js"></script>
  </head>
  <body>
    <p>Version: <script>document.write(_$.version);</script></p>
  </body>
</html>

開いてみてください。開いたら、この場合Version: 1.0と表示されるはずです。

取り敢えず、記事が長くなりすぎても悪いので、ここらへんで終わります。最後のところ分からなければ、コメント欄へ。
最後まで読んでくださりありがとうございました。

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

【HTML/CSS】開発環境構築 VSCode

開発環境構築

VSCodeに以下のプラグインをインストールしました。

  • Live Sass Compiler
     プロジェクト内のscssの変更を監視。
     scssファイルからcssファイルへのコンパイルを自動でしてくれる。
     Live Serverと競合しデッドロックした場合は、VSCodeを再起動する。

  • Live Server 
     右下の「Go Live」をクリックすると、PC上の仮想サーバが立ち上がる。
     基本的に開発は仮想サーバで動作を確認しながら行う。(右クリック→Open with Liveserver)

  • Prettier
     ソースを自動で整形してくれるツール。

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

widthが100%をオーバーするとき(flex-wrap神)

親要素に対して、子要素の幅が100%を超えるときの挙動の整理のため執筆しています。
※codepenですが、0.5×で見ていただくと綺麗にみることができます。

パターン1 | 親要素が600pxで子要素を50%ずつにする。

Frame 1.png

これは非常にシンプルです。
青セクションと赤セクションが半分になっていますね。


See the Pen
widthが100をオーバーするとき
by TakahiroOkada (@okalog)
on CodePen.


パターン2 | 子要素間に余白を持たせたい場合。

codepenを見てもらえば分かりますが、文字がつまっていて読みづらいですよね。
多くの方は要素間にmarginやpaddingで余白を持たせると思います。

Frame 2.png

これを行おうと、このようなコードを書いてみました。

sytle.css
.left{
  width:50%;
  background-color:#B0C2FF;
}
.right{
  width:50%;
  margin-left:50px;
  background-color:#FFA7A7;
}

結果はこうなります。


See the Pen
width整理-2
by TakahiroOkada (@okalog)
on CodePen.


親要素に対して、,子要素が100%を超えてしまったのでずれてしまっていますね。

パターン3 | widthにcalc指定をして子要素の大きさ100%に調整する。

CSSには、calc()という便利な機能があります。
参考(https://coliss.com/articles/build-websites/operation/css/how-calc-works-by-ire.html)

これを利用し子要素を100%になるように調整します。

See the Pen width整理-3 by TakahiroOkada (@okalog) on CodePen.

子要素が親要素に対して100%になりましたね。

番外編

実は最初flex-wrap:wrap;の指定なし、calc指定なし、margin-left:50px;だけでも綺麗にコンテナに収まっていました。

これはflex-wrapのデフォルトがno-wrapになっていたことで、コンテナからはみ出さないように指定されていたようです。
参考(https://developer.mozilla.org/ja/docs/Web/CSS/flex-wrap)
頭いいですよね。

See the Pen KKgwraz by TakahiroOkada (@okalog) on CodePen.

まとめ

いやー結構曖昧に使っていたので整理されてよかったです。

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

nginxで最小のwebサーバーを立ち上げてみる

はじめに

この記事を書いている人は普段はデータサイエンスっぽいことをしている人なのでweb系の知識は深くありません。
間違いのないように気をつけておりますが、どこか至らぬ点がございましたらご指南頂けますと幸いです。

モチベーション

プログラミング言語を習い始めると多くの場合、最初にHello worldされると思います。
流石にこのレベルだと簡単すぎな気もしなくはないですが、最も低レベルのことから順に高レベルにステップアップしていくという勉強方法を好む方にとっては良い慣習だと思います。
これのnginx版があると良いなぁと思っていたのですが、初学者目線からすると中々そのような記事等を見つけられませんでした。
なので、nginx版のHello worldを作成し、私のような初学者に感動を共有できればなぁと思い書き始めました(ちなみに初投稿です)。

前提

nginxはインストール済みとさせて下さい。
また、OSはMacとさせて下さい。

やってみる

 準備

まず、お好きな場所に以下のような構造を持つファイル群を作成して下さい。
内容は何でも構いませんが、面倒だと思うのでhtmlファイルの方は例を張っておきます。

data
├── images
│   └── example.png
└── www
    ├── 40x.html
    ├── example.html
    └── index.html
index.html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>tutorial of nginx</title>
</head>

<body>
    <h1>nginxの練習です</h1>
</body>

</html>
example.html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>example page</title>
</head>

<body>
    <h1>Hello World!!</h1>
</body>

</html>
40x.html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Error page</title>
</head>

<body>
    <h1>Some Error happend.</h1>
</body>

</html>

nginxの設定ファイルの編集

ここまでの準備ができたら後はnginxの設定ファイルを編集するだけです。
設定ファイルは/usr/local/nginx/conf, /etc/nginx, /usr/local/etc/nginxのいずれかのディレクトリ内にnginx.confという名前で存在するそうです(私の場合は一番最後のケースでした)。
nginx.confに対してまずは以下の内容をコピペして下さい。ちなみに、同じディレクトリにnginx.conf.defaultというファイルが有り、それをコピーすればいつでも最初の状態に復旧できるので安心して下さい。
その後、<dataまでのパス>の部分を個人の環境に合わせて編集して下さい。
(コメント書きまくったらコメントのほうが多くなってしまいました。。。笑)

# nginxの構成ファイルの基本4要素をモジュールと呼ぶ
# core, event, http, mailがモジュール

# 「ディレクティブ名 パラメータ;」 をまとめてディレクティブと呼ぶ
# 設定項目のこと
worker_processes  1;

# 中括弧を持つディレクティブはブロックディレクティブと呼ぶ
# 中身はコンテキストと呼ぶ

# eventsモジュールは省略不可
events {
    # ワーカープロセスが最大でいくつまでコネクションを処理できるかを指定
    worker_connections  1024;
}


http {
    # mime.types: MIMEタイプと拡張子の間の関係を記述
    # レスポンスの際にはmime.typesの記述に従って 拡張子 -> MIMEタイプ とマッピング
    include       mime.types;

    # 上でマッピングできなかった際にはしたのでマッピング
    default_type  application/octet-stream;

    # sendfile関数とやらがあるらしく、それの利用を許可するかどうかを指定
    # 込み入ってて難しい。。。
    sendfile        on;

    # クライアントの要求を待ってあげる最大時間
    # 65秒間要求がなければ接続を切断する
    keepalive_timeout  65;

    # serverディレクティブはhttpディレクティブ内に記述
    server {
        listen       80; # 80番ポートで待機
        server_name  localhost; # サーバの名前。リクエストのHostと比較される

        # ドキュメントルートを指定。指定された場所がサーバーでの配信対象になる
        root <dataまでのパス>/data;

        # URLのパスをサーバー上のパスにマッピングする
        location / {
            # rootの場合はlocationのパラメータが最後に結合される
            # aliasの場合は結合されない
            root   <dataまでのパス>/data/www;
        }

        # localhost/images/と指定された場合、上のlocationと下のlocation2つにマッチング
        # その際には前方一致でより長くマッチングするほうが選ばれる(マッチする/の数を長さとする?)
        # ex) localhost/images/の場合、上は長さ1, 下は長さ2なので下を選ぶ
        location /images/ {
            # rootなので<dataまでのパス>/data/images/とマッピング
            root   <dataまでのパス>/data;
        }

        # 40xのテキストフレーズが検出された場合、/40x.htmlを返す
        error_page   400 401 403 404  /40x.html;

        # /40x.htmlでマッチングを行う
        # = は完全一致
        location = /40x.html {
            root   <dataまでのパス>/data/www;
        }

    }
}

コマンドを叩く

ここまできたら後はコマンドを叩くだけです。
コンソールを起動して以下のコマンドを叩けば完了です。

$ nginx

確認してみる

折角webサーバーを立ち上げてみたので、何かリクエストを投げてみましょう。
webブラウザでhttp://localhost/index.htmlと入力してみて下さい。
「nginxの練習です」と表示されていれば成功です。逆に、表示されない場合には設定ファイルの記述が間違っているので、頑張って確認してみて下さい。
他にもhttp://localhost/images/example.pngと入力し画像が返されることを確認してみたり、わざとhttp://localhost/nofile.htmlのように入力してみて404エラーが返されることを確認してみると楽しいと思います。
ちなみに、設定ファイルに何らかのミスが有ることが判明した際には、編集後に以下のコマンドを叩いてください。
nginxに対して変更が反映されます。

$ nginx -s reload

nginxを停止させる

起動させたら停止させなければなりません。停止のためのコマンドは以下の2通りあります(本当はもっと色々な方法がある感じがしていますが、nginx純正の停止方法はこれらだと思います)。

$ nginx -s stop
$ nginx -s quit

英単語的に一緒なような気がして、何が違うの?と思いましたが、どうやら前者はいわゆるシャットダウンで、このコマンドを実行したらすぐに停止するようです。公式だとfast shutdownとよんでいます。
それに対して、後者はグレースフルシャットダウンと言い、このコマンド実行時にクライアントから届いたリクエストに関して捌き終わったらシャットダウンするそうです。公式でもgraceful shutdownとよんでいて、どうやらnginxに限らない一般的な用語なようです。

終わりに

以上で「nginxで最小のwebサーバーを立ち上げてみる」は終わりになります。
立ち上げてみることは出来たでしょうか?
あまり力になれないかも知れませんが、もし全然出来ない場合などありましたらコメント頂ければ、時間に余裕のあるときに極力お返事させていただこうと思っています。
読んでいただいた方が少しでもnginxを勉強してみたいと思って頂けたら私としては嬉しいです。
最後に、ここまで読んで頂きありがとうございました!

参考文献

[1]. "Beginner's Guide", Nginx, http://nginx.org/en/docs/beginners_guide.html, 2020年11月30日参照

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

Django+html+cssでサイドバーテンプレートを5分で作る

本記事の対象者

Djangoの公式ドキュメントで丁寧に書かれているチュートリアルは試した!けど、どうすればそれっぽい見た目のWebサイトを作れるんだ・・・?と悩んでいるそこの貴方!!!
「とにかくいい感じの固定サイドバー」があれば、良いwebサイトに見える気がしませんか?見えますよね!
この「とにかくいい感じの固定サイドバー」を5分で実装できればいいな〜〜と思っている良く深い貴方が対象です。

前提条件

  • 仮想環境の構築
  • Djangoのアプリ作成

が終わっている状態で以下の記事を読んでください。

実装環境

  • Django v.2.2.4
  • python v.3.7

実装

testapp : アプリ名 

階層
testapp --- __init__.py
        --- admin.py
        --- apps.py
        --- model.py
        --- tests.py
        --- urls.py
        --- views.py
        --- templates --- testapp --- base.html
                                  --- index.html
        --- static    --- css     --- main.css

とにかくコードをコピペする

base.html

{% load static %}
<html>
    <head>
        <title>5分で作ったWebサイト</title>
        <link rel="stylesheet" href="{% static 'css/main.css' %}">
        <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
        <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@700&display=swap" rel="stylesheet">
    </head>
    <body>
        <nav>
            <p>とにかくいい感じの固定サイドバー</p>
            <h1>5分で作ったWebサイト</h1>
            <div id="pageitem">
                {% include 'testapp/pagelist.html' %}
            </div>
        </nav>
        <header>
            <p>ついでに</p>
            <p>ヘッダーも作ろう</p>
        </header>
        {% block content %}{% endblock %}
    </body>
</html>

pagelist.html

<ul>
<li><a class="item" href="{% url 'testapp:index' %}">index</a></li>
<li><a class="item" href="{% url 'testapp:page1' %}">page1</a></li>
<li><a class="item" href="{% url 'testapp:page2' %}">page2</a></li>
</ul>

index.html

{% extends 'testapp/base.html' %}
{% block content %}
<main>
    <h1>indexページ</h1>
    <div>
        <p>hogehogehoge</p>
        <p>piyopiyo</p>
    </div>
</main>
{% endblock %}

page1.html

{% extends 'testapp/base.html' %}
{% block content %}
<main>
    <h1>page1ページ</h1>
    <div>
        <p>hogehogehoge</p>
        <p>piyopiyo</p>
    </div>
</main>
{% endblock %}

page2.html

{% extends 'testapp/base.html' %}
{% block content %}
<main>
    <h1>page2ページ</h1>
    <div>
        <p>hogehogehoge</p>
        <p>piyopiyo</p>
    </div>
</main>
{% endblock %}

main.css

p {
   font-family: "Roboto";
   font-size: 14pt;
   color: #44546A;
   margin: 0px;
}

body {
   display: grid;
   margin: 0;
   height: 100vh;
   grid-template-rows: 75px 1fr;
   grid-template-columns: 350px 1fr;
   grid-template-areas:
      "nav    header  "
      "nav    main    ";
}

nav {
   grid-area: nav;
   text-align: right;
   display: grid;
   margin: 0;
   min-height: 100vh;
   grid-template-rows: 2px 100px 1fr;
   grid-template-columns: 1fr;
   grid-template-areas:
       "stitle "
       "mtitle "
       "plist  ";
   padding : 20px;
   box-shadow: 2px 2px 4px gray;
   z-index: 2;
}

nav h1 {
   grid-area: mtitle;
   color: #2E75B6;
   font-family: "Roboto";
   font-size: 24pt;
   font-weight: bold;
   text-align: right;
}

nav p {
   grid-area: stitle;
   color: #44546A;
   font-family: "Roboto";
   font-size: 14pt;
   text-align: right;
}

nav div {
   grid-area: plist;
}

nav div ul{
   list-style: none;
}

nav div ul li a {
   color: #44546A;
   font-family: "Roboto";
   font-size: 12pt;
   font-weight: bold;
   text-align: right;
   background-color: #f4f5f7;
   border-left: 10px solid #44546A;
   padding: 5px 10px;
   margin: 0 0 10px 0;
   text-decoration: none;
   display: block;
}

nav div ul li a:hover {
   background: #8795a8;
   color: #FFF;
}

header {
   grid-area: header;
   background: #f4f5f7;
   margin : 0px;
   text-align: right;
   z-index: 1;
   padding: 10px;
   box-shadow: 1px 1px 2px gray;
}

header p {
   grid-area: stitle;
   color: #44546A;
   font-family: "Roboto";
   font-size: 12.5pt;
   text-align: right;
   margin : 0px;
}

main {
   overflow: auto;
   grid-area: main;
   margin : 0px;
}

main h1 {
   grid-area: mtitle;
   color: hsl(215, 22%, 34%);
   font-family: "Roboto";
   font-size: 20pt;
   font-weight: bold;
   text-align: left;
   padding-left: 15px;
}

main div p {
   text-align: center;
}

main::-webkit-scrollbar {
   display:none;
}

いろいろ直す

このままでは何も表示されないので以下のコードを書き換えます。

urls.py

ここを変更しないとサイドバーに並べたリンク集を踏んでもページが繊維しません。

from django.urls import path

from . import views

app_name = 'testapp'
urlpatterns = [
    path('', views.index, name='index'),
    path('page1/', views.page1, name='page1'),
    path('page2/', views.page2, name='page2'),
]

views.py

ここを変更しないとサイドバーに並べたリンク集を踏んでもページが繊維しません。

from django.shortcuts import render

def index(request):
    return render(request, 'testapp/index.html')

def page1(request):
    return render(request, 'testapp/page1.html')

def page2(request):
    return render(request, 'testapp/page2.html')

最後に

サポーターズ様主催の技育展に参加して早5ヶ月・・・。
この5ヶ月、有志で集まったDiscordの技育展サーバの中で毎週もくもく会を開いたり、メンバーを集めてハッカソンに出てみたり、いろいろやってきました。
今後もツヨツヨになれるよう頑張っていきます。

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