20190318のHTMLに関する記事は9件です。

HTML基礎まとめ

1.基本フォーマット

HTMLの基本的なフォーマット

<!DOCTYPE html>           ←ドキュメント形式
<html lang="ja">          ← HTML開始 (日本語)
  <head>               ← ヘッダ情報
    <meta charset="utf-8">                              ← 文字コード指定
    <title> サイトのタイトル </title>                    ← タイトル
    <meta name="description" content="サイトの説明">     ← サイト情報
  </head>
  <body>                  ← ボディ情報
    <h1> 見出し1 </h1>     ← 見出しサイズ:1~6
    <p> 内容 </p>
  </body>
</html>               ← HTML終了

2.リストの書き方

(1) Ordered List:番号付きのリスト
ol.PNG

<ol>
 <li>item1</li>
 <li>item2</li>
 <li>item3</li>
</ol>

(2) Unordered List:番号無しのリスト
ul.PNG

<ul>
 <li>item1</li>
 <li>item2</li>
 <li>item3</li>
</ul>

3.コントロールアイテム

input_text.PNG

<form>
  <label for="name">氏名</label>     ← ラベル
  <input type="text" id="name">      ← 入力フォーム
</form>

input_message.PNG
<form>
  <label for="message">メッセージ</label>     ← ラベル
  <textarea id="message"></textarea>         ← 入力フォーム
</form>

button.PNG
<form>
  <button>送信</button>     ← ボタン
</form>

select.png
<label for="product">商品
<select id="product">
  <option>商品A
  <option>商品B
  <option>商品C
</select>

checkbox.PNG
<fieldset>
  <legend>items</legend>
  <input type="checkbox" id="item1"><label for="item1">item1</label>
  <input type="checkbox" id="item2"><label for="item2">item2</label>
  <input type="checkbox" id="item3"><label for="item3">item3</label>
</fieldset>

radioPNG.PNG
<fieldset>
  <legend>items</legend>
  <input type="radio" name="items" id="item1"><label for="item1">item1</label>
  <input type="radio" name="items" id="item2"><label for="item2">item2</label>
  <input type="radio" name="items" id="item3"><label for="item3">item3</label>
</fieldset>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

独自データ属性(カスタムデータ属性)を使ってみた

独自データ属性(カスタムデータ属性)とは

html5で追加されたオリジナルの属性をつくれる仕組み。
data-〇〇=”値”  の形で記述する。〇〇の部分は自分で決められる。
・その値は全角もOK
・先頭に#や.をつけてもOK
・数値もOK
(idやclassでは先頭に数字、もしくは数字だけはNG)

CSS擬似要素のcontentをhtmlからattr()で取得してみた

attr()を使うと、擬似要素に同じスタイリングをしたい場合にコーディングが少なくて済む。
例のごとく下記にコーディング例を示す。

コーディング例

今回はブラウザ表示から。こんな感じの表示にしたい。
芸人のキャッチコピー的なテキストに擬似要素を使い、attr()も使ってみた。
qiitaGeininn.jpg

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>geininn</title>
    <link rel="stylesheet" href="../css/index.css">
</head>
<body>
    <div class="box">
        <div class="img"><img src="./img/kyozin.jpg" alt="オール巨人" width="159" height="212"></div>
        <div class="geininn" data-subtitle="~相方はオール阪神~">オール巨人</div>
    </div>
    <div class="box">
        <div class="img"><img src="./img/hitoshi.jpg" alt="松本人志" width="159" height="212"></div>
        <div class="geininn" data-subtitle="~浜田にしばかれる~">松本人志</div>
    </div>
    <div class="box">
        <div class="img"><img src="./img/emiko.jpg" alt="上沼恵美子" width="159" height="212"></div>
        <div class="geininn" data-subtitle="~えみちゃんねるでお馴染み~">上沼恵美子</div>
    </div>
</body>
</html>
index.css
.box{
    display: inline-block;
}
.geininn{
    font-size: 20px;
    font-weight: bold;
}
.geininn::after{
    content: attr(data-subtitle)"";
    display: block;
    color: #AAA;
    font-size: 15px;
}

参考

css擬似要素のcontentをhtmlからattr()で取得する
HTML5 【data-】 独自データ属性を使おう!

終わりに

結局divで囲んで同じクラス名つけてスタイリングすれば似たような事なのかなとも思いましたが、他の言語も使うようになってくるともっとメリットを感じれるのだろうと予想されるので、このやり方も覚えてこうと思います。

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

簡素なログインプログラム(パスワード認証のCGI)の作成

Abstract

Web通信やサーバーの動きの理解の一助のため、
「ただログインするだけのWebページを作ってみるとよい」
という助言を受け、実行してみることにした。

ログイン画面のhtmlは簡単にできたが、
本丸のバックエンドプログラムの作成でてこづっている。

ここでは、
「パスワード認証をするだけの簡素なCGI」
を作ることを目標にして、同時進行で様子をレポートしていきたいと思う。

自己紹介

プログラミング経験数週間の初心者。簡単なスマホアプリを作ることを目標にしています。
仕事にするかはわからないが、とにかく知識や技術をつけて、生きる力にしたいと思っています。

要件定義

・パスワード認証機能(管理人が定めた固定パスワードによるもの)

設計

1.ログインページのhtml(login.html)のformタグのメソッド"POST"を使ってブラウザによって送られてきたパスワード入力情報を、サーバーのCGI(login.php)にて受け取る。

2.受け取ったパスワード入力が、管理人が定めたパスワード"mintia"と一致するかどうか確かめ、
    一致する場合はブラウザにログイン先のページ(youkoso.html)を返して、
    一致しない場合はブラウザに「パスワードが間違っています」と表示させる。

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

HTMLとCSSの基礎

1. はじめに

今回はHTML,CSSの基礎を記載する.

タグとは

タグという用語が登場するので簡単に説明します.

<br>

これがタグです.
タグには上のように開始タグのみのものと

<p> これはテストです </p>

のように開始タグ< >と終了タグ</ >をセットで用いるものがあります.
タグによって機能が異なるので,調べて使ってください.

2. 内容

2.1. HTML5の基本構造

base.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>Webページタイトル</title>
</head>
<body>
    ここがWebブラウザに表示される部分
</body>
</html>

2.2. 表(テーブル)

table.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>Webページタイトル</title>
</head>
<body>
    2019年3月のカレンダー<br><br>
    <table>
        <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td></td><td></td><td></td><td></td><td></td><td>1</td><td>2</td></tr>
        <tr><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr>
        <tr><td>10</td><td>11</td><td>12</td><td>13</td><td>14</td><td>15</td><td>16</td></tr>
        <tr><td>17</td><td>18</td><td>19</td><td>20</td><td>21</td><td>22</td><td>23</td></tr>
        <tr><td>24</td><td>25</td><td>26</td><td>27</td><td>28</td><td>29</td><td>30</td></tr>
        <tr><td>31</td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
    </table>
</body>
</html>

2.3. リンク

link.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>Webページタイトル</title>
</head>
<body>
    <h2>そのまま開く場合</h2>
    <a href="http://www.google.com">Google</a><br>
    <a href="http://www.yahoo.co.jp">YAHOO! JAPAN</a><br>

    <h2>新規タブで開く場合</h2>
    <a href="http://www.google.com" target="_blank">Google</a><br>
    <a href="http://www.yahoo.co.jp" target="_blank">YAHOO! JAPAN</a><br>
</body>
</html>

2.4. 画像と動画の表示

同じディレクトリに保存されている画像と動画を表示する.

media.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>Webページタイトル</title>
</head>
<body>
    <!-- 動画, 画像のオプション一覧
        src="ファイル名"
        大きさ変更
            width(幅)×height(高さ)
            画面の大きさ(1080×720の場合):width="1080" height="720"
            動画の大きさ(100%×80%の場合):width="100%" height="80%"    ・・・%はウィンドウに対する大きさである
     -->
    <h2>動画一覧</h2>
    <!-- videoタグのオプション一覧
        コントロールインタフェース表示:controls
        自動再生:autoplay
        動画再生不可の画像表示例:poster="test.jpg"
    -->
    <video controls width="50%" height="50%"><source src="sample1.mp4"></video><br>
    <video controls width="720" height="480"><source src="sample2.mp4"></video><br>
    <h2>画像一覧</h2>
    <!-- imgタグのオプション一覧
        画像表示不可のテキスト表示例:alt="これはtest.jpgの画像です"
        表示位置調整:align=""
            alignの値:left,right,top,middle,bottom
     -->
    <img src="sample1.jpg" width="50%" height="50%"><br>
    <img src="sample2.jpg" width="500" height="500"><br>

    <h2>ファイルへのリンク</h2>
    <!--
        文字をリンクにする場合はimgタグを外してテキストにすればよい
        指定ファイル名で保存するリンク例:download="test.jpg"
        downloadはHTML5より実装
    -->
    <a href="sample1.jpg" download><img src="sample1.jpg" width="50%" height="50%"></a>
</body>
</html>

2.5. CSS

スタイルシートの指定には
(1) styleタグ内に指定する方法
(2) タグに直接記述する方法
(3) CSSファイルを別に作成する方法
が存在する.

2.5.1. HTMLに直接埋め込む

上の(1)と(2)の方法で,2.2. に記述したtable.htmlにスタイルシートを指定する.

style.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>Webページタイトル</title>
    <style>
        td{
            font-family:ヒラギノ丸ゴ ProN,HG丸ゴシックM-PRO;
            color:red;
            text-align:right;
            font-size:20px;
            border-right:1px solid black;
            border-bottom:1px solid black;
            padding:10px;
        }
    </style>
</head>
<body>
    <p><font size="8" color="blue" face="ヒラギノ丸ゴ ProN W4">2019年3月のカレンダー<br><br></font></p>
    <table>
        <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td></td><td></td><td></td><td></td><td></td><td>1</td><td>2</td></tr>
        <tr><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr>
        <tr><td>10</td><td>11</td><td>12</td><td>13</td><td>14</td><td>15</td><td>16</td></tr>
        <tr><td>17</td><td>18</td><td>19</td><td>20</td><td>21</td><td>22</td><td>23</td></tr>
        <tr><td>24</td><td>25</td><td>26</td><td>27</td><td>28</td><td>29</td><td>30</td></tr>
        <tr><td>31</td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
    </table>
</body>
</html>

2.5.2. CSSファイルを作成する

(3)のように,cssファイルを別に作成する際はHTMLファイルと連携させる必要がある.
連携する際は,HTMLファイルheadタグ内に次のように記述する.ただし,cssファイル名はtest.cssとする.

<link rel="stylesheet" type="text/css" href="test.css">

css ファイルの中身はHTMLファイルの<style></style>の中身の内容をそのまま記述する.

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

Webの仕事をしていない人が個人Webサービスを作ってみて得られた知見

自己紹介

Akahoriと申します。普段はIT業界と関係ない仕事をしていますが、今の仕事があまり面白くなく、
Webサービスを作ることにしました。Webサービスには無限の可能性があるように感じたためです。
最近の世の中のイケイケな会社は大体クラウドとかサービスやっています。
昔、数年SIerでWindows向け業務パッケージソフトを作っていたので基本的なIT知識はあります。

2018年夏ぐらいから書籍を買って勉強をしていましたが、2019年1月にconnpassにて3monthsServiceという
三ヶ月でサービスを開発しようというイベント見つけて参加させてもらったのが開発のきっかけです。感謝!
本記事は、私のようにWebに詳しくない人に向けた内容で、Webエンジニアの皆様には一般的なことかと思われます。
間違っている内容やもっと良い取り組み方があれば教えてもらえると大変助かります。

作ったサービス

EVENT MAP!という、connpassのイベントを地図検索できるサービスを作りました。
技術力の問題でいきなりマネタイズは難しいと考え、自分で使えるサービスであれば良いと考えたためです。
connpass公式サイトだと「東京都」までしか地域が絞れないため、行けないイベントが多いんですよね。
スタートアップの有名な人も、自分か、かなり親しい人が欲しいサービスは作るのに良いと言っています。

初期表示場所は設定ボタンにて東京、大阪、愛知、福岡、座標未登録から選べるようにしました。
検索ワードなども時間短縮のため記録できるようにしています。

https://event-map.info
map.png

動作環境・利用言語

フロントで多く使われており、サーバーサイドも書けるということでJavascriptをまず覚えたいと考えました。
その中で、新しめで書籍なども出ているライブラリとしてReactメインで開発することにしました。
Vue.jsなども迷いましたが、ReactはJavascriptを多く書くとのことで学習として応用が効きやすいと考えたためです。
Reactの勉強自体は開発時に始めたわけではなく、昨年に入門書を2冊読み、少し機能があるTODOアプリが作れるぐらいのレベルでした。
(当然のように、あまり理解していなかったことが後に判明します)

クライアント側言語:React+Redux, Material-UI
サーバー側言語:Node.js (Expressフレームワーク)
サーバー(PaaS):heroku (+mongoDB)
エディタ:Visual Studio Code

得られた知見

スムーズにいく部分でなく、やはり詰まったところから学べることが多いです。

デザイン調整はめちゃくちゃ難しい。最初にHTML/CSSを体系的に学んでおくべき。

CSSといえばmargin padding font-sizeなどの超基礎しか知らないレベルでした。displayによる違いも理解していませんでした。
さらにいきなりReactでMaterial-UIというCSSフレームワークを使ったことと、ReactのJSX記法による混乱もあり、
ページ数が極端に少ないサービスであるにも関わらず、体感上、総開発時間の3-4割の時間をデザイン調整に使ってしまっています。

PC版がようやく出来たと思っても、IEで崩れたり、スマホ対応があったり、さらにスマホ毎に画面サイズは違います。
Chrome、IE11、iPhone XS、iPhone SE、iPadなど、それぞれまともに表示できるようになると別のが崩れたりしていました。
ブラウザの表示倍率が100%でない場合に起こる問題などもありました。これは見なかったことにして難を逃れました。

またデザイン調整に入るのが早すぎたことも時間を取られた原因でした。作っていく内に使い勝手の悪さに自分で気づいたり、
予定していた機能が実は実装できなく削除するなどにより、途中からボタンが増えたり無くなったり移動したりしました。
中盤までは大まかな配置などの段階で留めておき、IEでパーツが別の所にお邪魔していても無視し機能が固まってから調整すべきでした。

CSSは要素同士が影響し合うため、おまじないコピペで解決しないのが難しいところです。
最初に、浅くても体系的にHTML/CSSを学んでいれば開発時間を短縮できたかと思います。

技術的な問題は英語で検索する方が早い

単純に英語と日本語での利用者数の問題もあり、日本語で結果が見つかっても古いバージョンでの解決方法、などということもしばしば。
広く一般的な問題や地域特有の問題以外は、最初から英語で検索した方が早いように感じました。
Chromeの翻訳で雰囲気を掴んで、崩れたところだけ原文を読みました。重要なのはコードなのでこれで十分でした。
日本語の記事で良いのがある場合は、コードの部分は英語であるため検索で引っかかるということもあります。

面倒な作業は評価、利用者の多いライブラリで。しかし実現が難しいこともある

最初はGoogleで適当にライブラリを検索していましたが、適当に選んだものやはり使い勝手が良くないことが多かったです。
試すのにも時間はかかるため、人気のものから試すべきと学びました。

また、日付を取り扱う定番ライブラリとしてMoment.jsというのがあり、とても便利なのですが、
これを知らなかったためJavascriptのDateオブジェクトで直接日付の取扱いを頑張ってしまっていました。
使い勝手悪いなと思う所はみんなが思っており、使いやすいライブラリが存在するかを早めに調べるべきでした。

一方、react-google-mapsというReactのライブラリ経由にてGoogle Maps Javascript APIを利用しマップ部分を
描画していたのですが、最終的にはライブラリを用いずに直接APIを利用し実装しました。
理由としては、納得のいかない挙動や、ライブラリ経由では利用できないAPIがあったことです。
また、利用者もライブラリでは直接のAPIほど多くないために技術的な問題の解決もスムーズにはいきません。
用語で検索しても何も出てこない場合、私のような技術の理解が浅い人は厳しいです。
今回のAPIのような、そのものの利用者が非常に多く使い勝手が良いAPIであれば、直接叩くことを早めに検討すべきでした。

デザインや機能改善以外にもやることは結構ある

想定以上にありました。私が気づいていないこともまだまだありそうです。教えて下さい!

SEO

Google Search Consoleの登録
Google Analyticsの登録
meta description、titleタグ等の設定
Lighthouseなどのツールによるチェック

マーケティング

Twitterカード、OGPの設定
独自ドメイン取得

法律の問題の検討

利用規約、プライバシーポリシーの整備
著作権の問題が生じる可能性のある箇所を再点検

利便性向上

問合せフォームの設置(googleフォーム便利でした)
PWA対応
DBに対する適切なインデックスの設定
DB等のデータ量増加が今後問題になることは無いか検討
適切なコメントを入れておくなどソースコードの保守性向上
SSL対応
CDNの利用検討(無料範囲でも便利でした)

セキュリティ

APIやサーバー、DB、サービスのアクセス許可、制限、保存手法などを見直す
Chromeのデベロッパーツールなどで不要なネットアクセスやコンソールログが無いか見直す
XSSなど広く知られたセキュリティの問題が無いか見直す

サービスをどう見てもらうのかを考える必要がある

なんとなく100人ぐらいに見てもらえて20人ぐらいにたまに使ってもらえるのかと考えていました。
私がTwitterなどのSNSを今更始めたばかりで繋がりが少ないということもありますが、
まず、アクセスしてもらえませんでした。
作っても、見てすらもらえないのでは始まりません。上の方に貼ったURLをスルーしたそこのあなた、作ったのはこれです(涙)

私のようにSNSをあまりやっていなかった場合、学習定着と、繋がりを広げることを兼ねてQiitaに記事を書く、LT登壇するなどアウトプットを増やすことも並行してやるべきだったと感じました。
友人が多い人でも、サービスの潜在顧客と層が異なるのであれば同一の問題を抱えるかもしれないので、早めに考えるべきかもしれません。
ツイートなどで広める場合、リリース時の見せ方も重要かと思いました。個人開発者のサービスリリース時のツイートを50人分集め分析した結果、私の中ではURLと同時に動いてる動画を貼るのがバズりやすいという結論に至りましたが、私はリリース後でしたので時既に遅しでした。ここは一つ、最初のリリースは無かったことに!

この段落は公開2日後の時点で書いていますが、多くの人に見ていただいて感無量です。
「サービス/アプリを作ったらQiitaに記事を書く」ことの重要性はかなり高いと学びました。
今後も積極的に書かせてもらいます。

コミュニティに参加すると開発が捗る

私が参加させてもらっている3monthsServiceのような、
サービス開発のイベント・コミュニティに参加したことで非常に開発が捗ったと感じています。

  1. 開発仲間ができます。
  2. 定期的に進捗を報告しなければということが、開発に対する後押しになります。
  3. どうしても解決できない問題を詳しい人に聞けるかもしれません。(何かお返ししましょう)
  4. 開発で得た知見などを共有できます。
  5. 定期的にお互いレビューを行うことで、UI/UX改善やセキュリティの問題など事前に解決できる可能性があります。

サービス開発はめちゃくちゃ楽しい!

最後になりますが、サービス開発はめちゃくちゃ楽しいです。想定より熱中できます。
特に中盤の、プログラムが動くようになってきたところが最高です。
勉強したい人、稼ぎたい人、就職や転職に役立てたい人、よければ開発しましょう!

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

Clipkitでギャラリーアイテムをカルーセルにする

はじめに

ギャラリーアイテムをカルーセルとして記事詳細ページに実装したいという要望にお応えすることがあったため、本記事でその手法をご紹介します。カルーセルのライブラリーは多数存在しますが、ここでは代表的なSlickを使用した実装方法をご紹介します。サンプルデザインについては、適宜調整してご利用ください。

サンプルデザイン

以下のような感じになります。「>」をクリックすると、次のスライドに進み、「<」をクリックすると、前のスライドに戻ります。それぞれタイトルとコメントが入力できるようになっています。PCでは画像背景をグレーでくり抜き、SPでは上下が画像によって可変になっています。

PCサンプルデザイン

Screenshot 2019-03-14 at 18.28.29.png

SPサンプルデザイン

Screenshot 2019-03-18 at 11.47.59.png

実装例

PCとSP共通準備

layout.html
    <!--SlickのCSSとJSを読み込む-->
    <link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.css"/>
    <script type="text/javascript" src="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.min.js"></script>

    <!--object-fit(IE対策→PCのみ!)-->
    <script src="{{ site.files | filename: "/theme/default/ofi.min.js" }}"></script>
    <script>$(function () { objectFitImages('.slick-slide .slide-img img') });</script>

<head>...</head>の中に以上のような実装を行います。また、jQueryを読み込んでいることが前提です。SlickにてCSSとJSのファイルをダウンロードしても良いですが、ここでは手っ取り早くCDNを読み込んでいます。PCでは画像のサイズ比率を保持するため、CSSにてobject-fitプロパティを使用しています。IEはobject-fitはに対応しておらず、画像の表示崩を起こすためofi.min.jsというファイルをダウンロードしています。objectFitImages()では該当クラス・IDをDOMで指定しています。全ての画像に適応したい場合は空欄にします。

PC

desktop.html
<div class="slider-container">
    <div class="slider">
        {% assign galleries = item.galleries %}
        {% for gallery in galleries reversed %}
        <div class="slick-slide">
            <div class="slide-img">
                {% if gallery.source_url == empty %}
                    <img data-lazy="{{ gallery.image_medium_path }}" alt="{{ gallery.title }}">
          {% else %}
                    <a href="{{ gallery.source_url }}">
                        <img data-lazy="{{ gallery.image_medium_path }}" alt="{{ gallery.title }}">
                    </a>
                {% endif %}
            </div>
            <div class="page-num"></div>
            <p class="slide-ttl">{{ gallery.title }}</p>
            <p class="slide-cmt">{{ gallery.comment | unescape | auto_link }}</p>
        </div>
        {% endfor %}
    </div>
</div>

<div class="page-num"></div>は空ですが、後に紹介するJSの実装でスライド番号を挿入します。不要でしたら削除してください。{% if gallery.source_url == empty %}...{% endif %}では、出典URLが入力されているならば、<a>タグを表示する仕組みです。

desktop.css
.slider-container {
  position: relative;
}
.slider {
  display: none;
  margin: 0 24px;
  overflow: hidden;
}
.slider.slick-initialized {
  display: block;
}
.slider-arrow {
  position: absolute;
  top: 50%;
  height: 36px;
  margin-top: -18px;  /* 高さの半分だけネガティブマージン */
  margin-left: -15px;
  margin-right: -15px;
  color: #000;
  line-height: 36px;
  font-size: 50px;
  cursor: pointer;
  z-index: 10;  /* 重要 */
}
.slider-prev {
  left: 0;
}
.slider-next {
  right: 0;
}
.slider-arrow.slider-next.fa.fa-angle-right.slick-disabled {
  visibility: hidden;
}
.slider-arrow.slider-prev.fa.fa-angle-left.slick-disabled {
  visibility: hidden;
}
.slick-slide {
  padding: 1.5em 0;
  color: #000;
  text-align: center;
  font-size: 1.1em;
  outline: 0;
  background-color: #fff;
  direction: ltr;
}
.slick-slide p {
  font-size: 12px;
  margin-bottom: 1px;
}
.slide-ttl {
  font-weight: bold;
  color: #000;
}
.slide-cmt {
  text-align: left;
}
.slider-counter {
  font-weight: bold;
  font-style: italic;
  font-size: 18px;
  text-align: center;
  color: #000;
}
.slick-slide .slide-img img {
  max-width: 100%;
  max-height: 100%;
  height: 500px;
  width: auto;
  margin: 0 auto;
  object-fit: contain;
  font-family: 'object-fit: contain;'; /*IE対策*/
}
.slide-img {
  background-color: whitesmoke;
}
desktop.js
var $slider_container = $('.slider-container');

$slider_container.each(function() {

  var $slider = $(this).find('.slider');

  $slider.on('init', function(event, slick) {
    $(this).find('.page-num').append('<div class="slider-counter"><span class="current"></span> / <span class="total"></span></div>');
    $(this).find('.current').text(slick.currentSlide + 1);
    $(this).find('.total').text(slick.slideCount);
  })
  .slick({
    appendArrows: $(this),
    // FontAwesomeのクラスを追加
    prevArrow: '<div class="slider-arrow slider-prev fa fa-angle-left"></div>',
    nextArrow: '<div class="slider-arrow slider-next fa fa-angle-right"></div>',
    infinite: true,
    speed: 300,
    slidesToShow: 1,
    lazyLoad: 'progressive'
  })
  .on('beforeChange', function(event, slick, currentSlide, nextSlide) {
    $(this).find('.current').text(nextSlide + 1);
  })
  .on('afterChange',function(event, slick, currentSlide, nextSlide){
    var slideNum = currentSlide + 1;
  });
});

関数には.eachメソッドを利用し、1記事に複数のギャラリーアイテムが存在しても、お互いの動作に干渉しないようにしています。スライド速度はミリ秒設定です。ここでは、speed: 300(0.3秒)で設定してます。infinite: trueでスライドが無限ループします。falseにすると、有限になります。lazyLoad: 'progressive'でHTMLのdata-lazy属性の箇所で画像遅延読み込み行います。

SP

smartphone.html
<div class="slider-container">
    <div class="slider">
        {% assign galleries = item.galleries %}
        {% for gallery in galleries reversed %}
        <div class="slick-slide">
            <div class="slide-img">
                {% if gallery.source_url == empty %}
                    <img data-lazy="{{ gallery.image_medium_path }}" alt="{{ gallery.title }}">
          {% else %}
                    <a href="{{ gallery.source_url }}">
                        <img data-lazy="{{ gallery.image_medium_path }}" alt="{{ gallery.title }}">
                    </a>
                {% endif %}
            </div>
            <p class="slide-ttl">{{ gallery.title }}</p>
            <p class="slide-cmt">{{ gallery.comment | unescape | auto_link }}</p>
        </div>
        {% endfor %}
    </div>
</div>

特にスマートフォンではデバイスによって、画像の読み込みに非常に時間がかかります。ロード時間短縮のために、画像遅延読み込みdata-lazy属性をsrc属性の代わりに使用します。

smartphone.css
.slider-container {
  position: relative;
  width: 100%;
}
.slider {
  display: none;
  overflow: hidden;
}
.slider.slick-initialized {
  display: block;
}
.slider-arrow {
  position: absolute;
  top: 50%;
  height: 36px;
  margin-top: -18px;  /* 高さの半分だけネガティブマージン */
  margin-left: 5px;
  margin-right: 5px;
  color: #fff;
  line-height: 36px;
  font-size: 40px;
  cursor: pointer;
  z-index: 10;  /* 重要 */
}
.slider-prev {
  left: 0;
}
.slider-next {
  right: 0;
}
.slider-arrow.slider-next.fa.fa-angle-right.slick-disabled {
  visibility: hidden;
}
.slider-arrow.slider-prev.fa.fa-angle-left.slick-disabled {
  visibility: hidden;
}
.slick-slide {
  padding: 1.5em 0;
  color: #000;
  text-align: center;
  font-size: 1.1em;
  outline: 0;
  background-color: #fff;
  direction: ltr;
}
.slick-slide p {
  font-size: 12px;
  margin-bottom: 1px;
}
.slide-ttl {
  font-weight: bold;
  color:#000;
}
.slide-cmt {
  text-align: left;
}
.slider-counter {
  font-weight: bold;
  font-size: 14px;
  text-align: right;
  color: #000;
}
smartphone.js
var $slider_container = $('.slider-container');

$slider_container.each(function() {
  var $slider = $(this).find('.slider');

  $slider.on('init', function(event, slick) {
    $(this).find('.slide-img').append('<div class="slider-counter">【<span class="current"></span> / <span class="total"></span>】</div>');
    $(this).find('.current').text(slick.currentSlide + 1);
    $(this).find('.total').text(slick.slideCount);
  })
  .slick({
    appendArrows: $(this),
    // FontAwesomeのクラスを追加
    prevArrow: '<div class="slider-arrow slider-prev fa fa-angle-left"></div>',
    nextArrow: '<div class="slider-arrow slider-next fa fa-angle-right"></div>',
    infinite: true,
    speed: 50,
    slidesToShow: 1,
    adaptiveHeight: true,
    lazyLoad: 'progressive'
  })
  .on('beforeChange', function(event, slick, currentSlide, nextSlide) {
    $(this).find('.current').text(nextSlide + 1);
  })
  .on('afterChange',function(event, slick, currentSlide, nextSlide){
    var slideNum = currentSlide + 1;

    $(this).find('.current').text(currentSlide + 1);
  });
});

スマホの場合、スライド速度はspeed: 50と設定しています。スマホのデバイスによってはスワイプの感度が非常に悪い機種があるため、推奨設定秒数は100ミリ秒(0.1秒)以下となります。adaptiveHeight: trueで画像の縦幅に応じて、ギャラリーの高さをを変更しています。SPもPCと同様にlazyLoad: 'progressive'でHTMLのdata-lazy属性の箇所で画像遅延読み込み行います。

参考

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

ページ内ジャンプをjsを使わずに!

GOAL

ページ内ジャンプをjsを使わずにhtml要素だけで実装

how to

test.html
<a href="#bo1">ここを押すとジャンプします</a>

<a name="box1"></a>

こんな感じで2つのaタグを、リンク先とname属性で繋げてジャンプします。
ポイントはリンク先に#をつけること。

参考サイト

特定の場所に移動したい!HTMLでジャンプする方法【初心者向け】

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

seleniumでtryとifを合わせる【python】

やりたかったことの最終型を先に書く。

test.py
def test(huga)
    try:
        # 要素1の取得
        hoge_1 = driver.find_element_by_xpath("//*[@class='hoge class']").text
        # 要素2の取得
        piyo_1 = driver.find_element_by_xpath("//*[@id='root']/div/div/span").text
        # 上記パスの値を変えるシステムをクリック
        driver.find_element_by_xpath("//*[@id='root']/div").click
        # 要素1と同パスの要素を取得
        hoge_2 = driver.find_element_by_xpath("//*[@class='hoge class']").text
        # 要素2と同パスの要素を取得
        piyo_2 = driver.find_element_by_xpath("//*[@id='root']/div/div/span").text
        # 要素1変更前と変更後で差異が出たか判定
        if hoge_1 == hoge_2:
            result = "NG(要素1の差異無し)"
        # 要素2変更前と変更後で差異が出たか判定
        elif piyo_1 == piyo_2:
            result = "NG(要素2の差異無し)"
        # 上記二つの判定に掛からなかったらelseへ進む
        else:
            result = "OK(要素1と要素2の変更を確認)"
    # xpath不整合時のエラー(ifに入る前にエラーになったらここ)
    except:
        result = "要素取得失敗"
    # 結果はどうあれ、resultの値を返す
    return result

tryの中にifを入れ、二つの要素を見た結果を返す、途中で何かミスったら強制的にエラーになる処理がしたかったので作成。
あと値を変える為のクリックについては至極個人的な処理なもんでたぶん使う人はいないので、基本的に消して頂きたい。
上記のコードは自作の別プログラムの参照(ローカルライブラリのインポート)をしているので、そちらに値を返すためにdefとreturnを使用している。

単純に一つのプログラムで処理するのは下記。
クリックを消し、要素は一つの要素を比較。

test.py
try:
    # 要素1の取得
    hoge = driver.find_element_by_xpath("//*[@class='hoge class']").text
    # 要素2の取得
    piyo = driver.find_element_by_xpath("//*[@class='piyo class']").text
    # 差異の判定
    if hoge == piyo:
        print("NG(差異無し)")
    # 判定に掛からなかったらelseへ進む
    else:
        print("OK(差異有り)")
# xpath不整合時のエラー(ifに入る前にエラーになったらここ)
except:
    print("要素取得失敗")

ただprintにしただけ。

別プログラム参照でreturn使う時に変数の値を見たいって時は下のやつ。

test.py
def test(huga)
    try:
        # 要素1の取得
        hoge_1 = driver.find_element_by_xpath("//*[@class='hoge class']").text
        # 要素2の取得
        piyo_1 = driver.find_element_by_xpath("//*[@id='root']/div/div/span").text
        # 上記パスの値を変えるシステムをクリック
        driver.find_element_by_xpath("//*[@id='root']/div").click
        # 要素1と同パスの要素を取得
        hoge_2 = driver.find_element_by_xpath("//*[@class='hoge class']").text
        # 要素2と同パスの要素を取得
        piyo_2 = driver.find_element_by_xpath("//*[@id='root']/div/div/span").text
        # 要素1変更前と変更後で差異が出たか判定
        if hoge_1 == hoge_2:
            result = "NG(要素1の差異無し)"
        # 要素2変更前と変更後で差異が出たか判定
        elif piyo_1 == piyo_2:
            result = "NG(要素2の差異無し)"
        # 上記二つの判定に掛からなかったらelseへ進む
        else:
            result = "OK(要素1と要素2の変更を確認)"
    # xpath不整合時のエラー(ifに入る前にエラーになったらここ)
    except:
        result = "要素取得失敗"
    # 結果はどうあれ、resultの値を返す
    return result,hoge_1,piyo_1,hoge_2,piyo_2

最後のreturnに「,」と見たい値の変数を入れる。

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

iOS、Safariの<input type="file" multiple>で発生するエラーに対応した際の備忘録

はじめに

とあるサイトを制作していた時、iOS、Safariの<input type="file" multiple>でファイルを選択した場合にエラーが発生する事象に遭遇しました。
ネット上で有益な情報を見つけられなかったので、備忘録として残します。

事象

下記のような、選択したファイル名をリスト表示させるものを作る際に発生しました。

ソース

HTML
<form action="" method="get">
<div>
<ul>
</ul>
<label>
<input type="file" multiple="multiple">
</label>
</div>
</form>
JavaScript
$(function () {
  /*------------------------------------------
    ファイルアップロード
  --------------------------------------------*/ 
  $('body').on('change', 'input[type="file"]', function() {
    var $this = $(this)
    var $ul = $this.parent('label').siblings('ul')
    var listHtml = ''

    if($ul.length > 0) {
      var files = $this[0].files
      var filesLength = files.length

      // ファイルを1件以上選択している場合
      if(filesLength > 0) {
        // HTMLを生成
        for(var i = 0; i < filesLength; i++) {
          listHtml += '<li>' + files[i].name + '</li>'
        }

        // HTMLに反映
        $ul.html(listHtml)
      } else {
        // ファイルの選択をキャンセルした場合
        // リストを削除する
        $ul.html('')
      }
    }
  })
})

See the Pen MultipleFileSample01 by N/NE (@inumberx) on CodePen.

発生端末

OS iOS 12.1.4
端末 iPhoneX
ブラウザ Safari、Google Chrome

現象

<input type="file" multiple>でファイルを複数選択した後に、再度ファイルを再選択・キャンセルすると下記画像のようなエラーが発生するというものです。

img_001.jpg

  • 問題が発生したため、このWebページが再読み込みされました。というメッセージが表示される

img_002.jpg

  • "https://XXX/YYY/ZZZ"で問題が繰り返し起きました。というメッセージが表示される

発生タイミング

色々と検証した結果、エラーは下記のようなタイミングで発生しているようでした。

  • ファイル選択済の状態でファイルを再選択する
  • ファイル選択済の状態でキャンセルする
  • ファイルを選択した時に、既にファイル選択済の他の<input type="file" multiple>が表示状態(display:none;以外)で存在する

対応方法

エラーを発生させないためには、ファイルを選択した時に既にファイル選択済の<input type="file" multiple>がdisplay:none;以外で存在していてはいけません。
そこで、ファイルを選択した時にJS(jQuery)でその要素を非表示にし、新しく空の<input type="file" multiple>を作ることによってエラーが発生しないようにしました。

ソース

HTML
<form action="" method="get">
<div>
<ul>
</ul>
<label>
<input type="file" multiple="multiple">
</label>
</div>
</form>
CSS
input[type="file"][multiple="multiple"].ios {
position: absolute;
opacity: 1;
z-index: 1;
}
input[type="file"][multiple="multiple"].ios + input[type="file"][multiple="multiple"] {
display: none;
}
JavaScript
$(function () {
  /*------------------------------------------
    ファイルアップロード
  --------------------------------------------*/
  // iOSの場合
  // すでにファイルを選択済みの<input type="file" multiple>の場合、ファイルを再選択・キャンセルした時にブラウザのエラーが発生するので個別対応を行う
  if(isIOs && $('input[type="file"][multiple="multiple"]').length > 0) {
    var $file = $('input[type="file"][multiple="multiple"]')
    var fileLength = $file.length

    for(var i = 0; i < fileLength; i++) {
      var $thisFile = $($file[i])
      // inputを複製
      var $cloneFile = $thisFile.clone(true)
      // 複製した要素にクラスを付与
      $cloneFile.val('').addClass('ios')
      // 複製した要素はabsoluteで複製元の要素に被せるため、親要素をrelativeにする
      $thisFile.parent().css(
        {
          'position': 'relative',
          'min-width': $thisFile.outerWidth(true) + 'px',
          'min-height': $thisFile.outerHeight(true) + 'px'
        }
      );
      // 複製した要素をDOMに追加
      $thisFile.before($cloneFile)
    }

    // 複製した要素に隣り合う<input type="file" multiple>がタッチされた時の処理
    $('body').on('touchstart', 'input[type="file"][multiple="multiple"].ios + input[type="file"][multiple="multiple"]', function() {
      // 何もしない
      return false
    })

    // サブミット時の処理
    $('body').on('submit', function() {
      // 複製した要素を削除する
      $('input[type="file"][multiple="multiple"].ios').remove()
    })
  }

  $('body').on('change', 'input[type="file"]', function() {
    var $this = $(this)
    var $ul = $this.parent('label').siblings('ul')
    var listHtml = ''

    if($ul.length > 0) {
      var files = $this[0].files
      var filesLength = files.length

      // ファイルを1件以上選択している場合
      if(filesLength > 0) {
        // HTMLを生成
        for(var i = 0; i < filesLength; i++) {
          listHtml += '<li>' + files[i].name + '</li>';
        }

        // HTMLに反映
        $ul.html(listHtml)
      } else {
        // ファイルの選択をキャンセルした場合
        // リストを削除する
        $ul.html('')
      }
    }

    // iOSの場合
    if($this.hasClass('ios')) {
      // inputを複製
      var $cloneFile = $this.clone(true)
      // 複製した要素のvalueを空にする
      $cloneFile.val('')
      // すでに存在するinputを削除する
      $this.siblings('input[type="file"][multiple="multiple"]').remove()
      // 複製した要素をDOMに追加
      $this.removeClass('ios').before($cloneFile)
    }
  })
})

/*------------------------------------------
 iOSチェック
--------------------------------------------*/
function isIOs() {
  var ua = navigator.userAgent
  var bw = window.navigator.userAgent.toLowerCase()

  // iOSの場合
  if(ua.indexOf('iPhone') > 0 || ua.indexOf('iPod') > 0 ) {
    return true
  }

  return false
}

See the Pen MultipleFileSample02 by N/NE (@inumberx) on CodePen.

問題点

  • 常に「ファイル未選択」と表示される → 選択したファイル数を「ファイル未選択」の文言の上に無理やり被せる?
  • 根本的な解決方法ではない気がする → もっと良い解決方法をご存知の方がいらっしゃったらご教示ください
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む