20200726のHTMLに関する記事は7件です。

【初心者でもわかる】インライン要素に指定できないcss

どうも、7noteです。インライン要素に指定しても効かないcssの話。

cssってたくさんありすぎて、どれがどう反映されるのか覚えるだけでも大変なのに、
要素によっては効かないものまであるという初心者にはかなり厄介なものかなと思います。

今回はそんなcss初心者の人向けに「インライン要素には効かないcss」をまとめて紹介していきます。

インライン要素に指定しても効かないcss一覧

・ margin(の上下)

間違った記述.css
span {
    margin: 100px 0; /* ← 効きません */
}

インライン要素にはmarginの上下を指定することはできません!
親要素のブロック要素に指定するか、「display: inline-block;」「display: block;」を当ててインライン要素ではなくしてからなら効きますよ。

・ margin(auto)

間違った記述.css
span {
    margin: 0 auto; /* ← 効きません */
}

インライン要素にはmarginのautoは効きません。左右に余白をとる場合は実数値のpxなどを使うようにしましょう。

・ text-align

間違った記述.css
span {
    text-align: center; /* ← 効きません */
}

これは経験者の人でもやってしまうことあるのではないでしょうか。私はいまだにたまに間違えます。
「text-align: center;」はブロック要素に指定するものなので、「ブロック要素の中にあるコンテンツを中央揃えにしなさい」というcssなので、効きません。ちなみにinline-blickの要素にも「text-align: center;」は効きません。

・ width,height(imgタグを除く)

間違った記述.css
span {
    width: 100%; /* ← 効きません */
    height: 200px; /* ← これも効きません */
}

インライン要素に横幅と高さは指定できません。ただし例外があり、imgタグには横幅と高さを指定することができます。

主要なcssでインライン要素に効かないcssは以上ですかね。
他にも厳密にはbox-sizing: border-box;とかも横幅が効かないので同様に効かないのですが、そういうものは省きました。

まとめ

いろいろ調べたのですが、インライン要素には何が効かないのかを全部まとめてるサイトは少なかったので今回記事にしました!
このへんの話は初心者はけっこう詰まりやすいし、なかなかミスに気づかないことも多くて余計な時間をくうことになるので覚えておいて損はないです!しっかり覚えておきましょう!

おそまつ!

(コメント・質問・ソースの指摘等なんでもウェルカムです!初心者の方でも気軽に質問ください!)

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

textareaの文字を色分けする(しているように見せる)方法を考えてみた

codepenやGASのエディタでは、入力された文字は次々と色分けされていきます。本記事ではそんな機能を、つまり入力された文字をそれぞれ色分けする機能を、JavaScriptのライブラリを駆使して「簡単に」再現してみようと思います。…再現と書きましたが、原理は根本的に異なるものであるということはあしからず。

sfdfg.png
サンプルのスクリーンショット
CSSを入力したら、こんな具合に色分けする。

必要なもの

  • highlight.js (JavaScriptライブラリ)
  • JavaScript/CSSについての最低限の知識

0. はじめに知っておくべきこと

ご存知の方もいらっしゃるかもしれませんが、textarea内の文字をそれぞれ別の色に変えることはできません(textareaの文字色を赤にしてSVGフィルターをかけたspanを各文字の位置に重ねるという泥臭い方法はありますが、機能性も低くハイコスト・ローリターンです)。

ではどうするのか……以下のようにすればよいのです。

  • textareaの上に「textareaではないがtextareaと同じスタイル」の要素Aを被せる
  • textareaの文字色を透明にする
  • textarea内の文章を要素Aに連動させる
  • 要素A内に収められた文章をハイライト用ライブラリ(highlight.js)でじっくり料理する

1. 要素Aを作る

ここでいう要素Aは、highlight.jsを適用できるような要素でなければなりません。つまり

sample.html
<html>
  <head>
    <link rel="stylesheet" href="style.css">

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/dracula.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/atom-one-dark.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
  </head>

  <body>

    <!--以降のHTMLの例はここから-->
    <div class="twrap">
      <textarea></textarea>

      <pre><!--要素A-->
        <code class="css"></code>
      </pre>
    </div>
    <!--ここまでのみ表示-->

    <script src="script.js"></script>
  </body>
</html>

こんな具合です。

2. 要素Aとtextareaの見た目を合わせる

まず我々には二つの道があります。

  • textareaをスクロールさせる(textareaの高さを固定する)
  • textareaをスクロールさせない(textareaの高さを可変にする)

本記事では「textareaをスクロールさせない」を選びます。

Tips あるいは失敗談
textareaをスクロールさせる方が見栄えは良いかもしれません。textareaのscroll量を要素Aに連動させるのは簡単ですし、以降の説明にある作業の多くが不要になりますからね。ですが、そのページがiPhoneからの閲覧を想定しているものならば、やめた方が良いです。iPhoneの慣性スクロールにおいては、上端あるいは下端を越えてその要素を引っ張ることができますが、そのうち上端を越える場合、JavaScript側ではscrollイベントが更新されず、そのscroll量はマイナスになってくれません。その間、textareaと要素Aの位置関係に齟齬が生まれてしまいます。

まずはtextareaと要素Aのスタイルを合致させましょう。

style.css
.twrap textarea {
  -webkit-appearance: none;
  border: 1px solid #aaa;
  border-radius: 0;
  box-sizing: border-box;
  font-size: .8rem;
  height: 100%;
  margin: 0;
  padding: 0 .25em;
  resize: none;
}
.twrap pre {
  margin: 0;
  padding: 0;
  pointer-events: none;/*要素Aを触れなくする*/
}
.twrap pre code {
  border: 1px solid transparent;
  box-sizing: border-box;
  font-size: .8rem;
  height: 100%;
  margin: 0;
  padding: 0 .25em;
  white-space: pre-wrap;
  word-break: break-all;
}

3. textareaと要素Aを重ねる

一度textareaと要素Aの位置関係を確認してみましょう。

sample.html
    <div class="twrap">
      <textarea></textarea>

      <pre><!--要素A-->
        <code class="css"></code>
      </pre>
    </div>

この場合、.twrapposition: relative;を、要素Aにposition: absolute;を設定しましょう。

style.css
.twrap {
  position: relative;/*new*/
}
.twrap textarea {
  -webkit-appearance: none;
  border: 1px solid #aaa;
  border-radius: 0;
  box-sizing: border-box;
  font-size: .8rem;
  margin: 0;
  padding: 0 .25em;
  resize: none;
}
.twrap pre {
  left: 0;/*new*/
  margin: 0;
  padding: 0;
  pointer-events: none;
  position: absolute;/*new*/
  top: 0;/*new*/
}
.twrap pre code {
  border: 1px solid transparent;
  box-sizing: border-box;
  font-size: .8rem;
  margin: 0;
  padding: 0 .25em;
  white-space: pre-wrap;
  word-break: break-all;
}

4. textarea内の文章を要素Aに連動させる&要素Aをハイライト

script.js
var textarea = document.querySelector(".twrap textarea");
var dummy = document.querySelector(".twrap pre code");

textarea.oninput = function() {
  dummy.innerText = textarea.value + "\u200b";//textareaの値の最後が改行コードだった場合に対応するためのゼロ幅スペース
  hljs.highlightBlock(dummy);
}

5. textareaと要素Aをリサイズする

これをしないと、textareaと要素Aそれぞれの文字の位置がズレます。

Googleで検索すると、textareaのリサイズについての記事が幾つか散見されます。offsetHeightとscrollHeightの違いなどをもとにwhileループで最適の大きさを求めるものなどです。スマートですね。ですが本記事の場合、もっとコストの低い良いものがあるので、それらは使いません。

ではどうするのか……要素Aのありのままの大きさを測り、それを.twrapheightとして反映すれば良いのです。そしてtextareaと要素Aにheight: 100%;をかけておけば、それらの大きさは.twrapの大きさに依存するようになります。

下準備:スタイルを合わせる

style.css
.twrap {
  position: relative;
}
.twrap textarea {
  -webkit-appearance: none;
  border: 1px solid #aaa;
  border-radius: 0;
  box-sizing: border-box;
  font-size: .8rem;
  height: 100%;/*new*/
  margin: 0;
  padding: 0 .25em;
  resize: none;
}
.twrap pre {
  height: 100%;/*new*/
  left: 0;
  margin: 0;
  padding: 0;
  pointer-events: none;
  position: absolute;
  top: 0;
}
.twrap pre code {
  border: 1px solid transparent;
  box-sizing: border-box;
  font-size: .8rem;
  height: 100%;/*new*/
  margin: 0;
  padding: 0 .25em;
  white-space: pre-wrap;
  word-break: break-all;
}
.twrap pre code.resizing {
  height: unset;/*new*/
}

リサイズ用のコードを入れる

script.js
var twrap = document.querySelector(".twrap");
var textarea = twrap.querySelector("textarea");
var dummy = twrap.querySelector("pre code");

resizeTA();

textarea.oninput = function() {
  dummy.innerText = textarea.value + "\u200b";//textareaの値の最後が改行コードだった場合に対応するためのゼロ幅スペース
  hljs.highlightBlock(dummy);
  resizeTA();
}

function resizeTA() {
  dummy.classList.add("resizing");//ありのままの大きさに戻す
  twrap.style.height = (dummy.scrollHeight + 20) + "px";//念の為に20pxほどマージンを取っている
  dummy.classList.remove("resizing");
}

6. textareaの文字色と要素Aの背景色を透明にし、highlight.jsでfont-weight: bold;にされたspanをnormalにする

Tips あるいは失敗談
本記事ではtextareaと要素Aのフォントをmonospace系にしていますが、これは等幅フォントの利便性を鑑みた結果です。monospace系は文字サイズさえ同じならば、如何な文字も、あるいは太字やイタリック体であろうと、同じ幅になるためです。いえ、そうなる予定でした。しかしiPhoneの場合、太字にすると幅が少しだけ大きくなります。PCやAndroidだと同じ幅なのに…。そんなわけで、太字も無理やり通常の太さに戻してしまっているので、必ずしもmonospace系にこだわる必要はないでしょう。

style.css
.twrap {
  position: relative;
}
.twrap textarea {
  -webkit-appearance: none;
  border: 1px solid #aaa;
  border-radius: 0;
  box-sizing: border-box;
  caret-color: #000;/*new*/
  color: transparent;/*new*/
  font-family: monospace;/*new*/
  font-size: .8rem;
  height: 100%;
  margin: 0;
  padding: 0 .25em;
  resize: none;
}
.twrap pre {
  height: 100%;
  left: 0;
  margin: 0;
  padding: 0;
  pointer-events: none;
  position: absolute;
  top: 0;
}
.twrap pre code {
  background: transparent;/*new*/
  border: 1px solid transparent;
  box-sizing: border-box;
  font-family: monospace;/*new*/
  font-size: .8rem;
  height: 100%;
  margin: 0;
  padding: 0 .25em;
  white-space: pre-wrap;
  word-break: break-all;
}
.twrap pre code.resizing {
  height: unset;
}
.twrap pre code span {
  font-weight: normal;
}

あとは各要素の大きさに影響を与えない範囲でデザインすれば完成です。

おわりに

iOSを開発されている方々に一言物申したいですね。iOSには面白い機能がたくさんあり、彼らの独創性・発想力、目を見張るものがあると思います。利便性を謳いたくなるのも分かります。ですがその前に、計画性と協調路線の存在にしっかりと目を向けてもらいたいですね。ここまでで挙げた通り、iOSのせいで余計な回り道をさせられています。この例に限った話ではないです。独自路線を突っ走り過ぎると嫌われますよ。

サンプル

http://topia.wdfiles.com/local--code/css-parser-1/1

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

初心者によるプログラミング学習ログ 382日目

100日チャレンジの382日目

twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
382日目は、

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

リンクチェック方法のまとめ

ウェブサイト/ウェブサービスではリンクが正しく張れているかの確認は大事です。せっかくユーザがリンクを踏んだのに 404 になってしまってはユーザ体験を大きく損なってしまいますので。

数ページ程度のサイトなら手動でテストすることも可能ですが、多数のページを抱えるサイトでは手動では限界があります。ローンチ時は人海戦術でなんとか手動確認できても、長らく運営している間にコンテンツの更新が積み重なるとリンク切れの場所も多々でてくるでしょう。

ということで、リンクチェックを自動的に行う方法についてまとめてみます。

リンクの種類

まず最初にリンクにはどのような種類があるのか整理しておきます。

a href

リンクと言って一番最初に思いつくのが a タグの href 要素です。リンクターゲットをクリックすることで href 要素で指定されたリンク先に遷移します。

リンク先にはサイト内リンクと外部サイトへのリンクがあります。また、ページ自体へのリンクと id リンクがあります。ページが存在してターゲットの id が存在しない場合、通常はページの先頭を表示しますが、これは 404 などのエラーにならないですがユーザ体験は損なっています。404 エラーを発生しない分、検出が困難でもあります。

a タグが最初から HTML に書かれている場合と、JavaScript によって動的に生成される場合があります。一般的に後者のリンクチェックは難易度が高くなります。

リソース

img src による画像、js や css ファイル、css ファイル中で指定される画像などです。

a タグと同様、HTML に書かれている場合と、動的に生成される場合があります。

動的処理によるページ遷移

JavaScript で処理した結果、location.href で別ページに遷移するものです。

外形チェック型

サイトに対して網羅的にチェックするのではなく、本番環境を運用している間に結果的に発生した 404 を検出する方法です。すべてのリンク切れを発見することはできませんが、一方で JavaScript で動的に生成されるリンクでもチェックが可能です。

アクセスログ

ウェブサーバのアクセスログから 404 を返したものを調べる方法です。現実のアクセスログにはアタックの痕跡などノイズも多数残されていますので、それらを除去する必要があります。

原理的に全てのリンク切れを検出することは困難ですが、検出できないリンク = ユーザがめったに踏まないリンクだから軽視して良いという考え方もありだと思います。

Google Search Console

Google Search Console のカバレッジでは、404 を含む様々なエラーを検出することができます。Google のクローラがアクセスした結果ですので、ある程度網羅的なエラー検出が期待できます。Google クローラも最近は簡単な JavaScript なら実行してくれるそうなので、動的処理のリンクも少しはカバーされると期待できます。

欠点としては、Google のクローラが一巡するまでは結構な時間がかかるということです。特に新規のサイトや規模が小さくて Google から重要でないと判断されているサイトはクロール頻度が低くなり、より多くの時間が掛かります。

ブラウザの開発ツール

例えば Chrome のデベロッパーツールでは、Network タブで読み込んでいるリソースと読み込み状況を確認できます。ページ単位でのチェックなのでサイト全体を調べることはできませんが、方法の一つとして覚えておきたいです。

静的解析型

静的に生成された HTML の場合、静的解析でリンクチェックを行うことができます。

孤島発見器

孤島発見器 は Windows 上で動作する静的リンクチェッカです。個人的に長らく愛用していたツールです。最終更新日が 2001年4月26日と古いのですが、Windows 10 でも動作します。ページ内リンクにも対応している優れものなのですが、name 属性のみで id 属性に対応していません。時代的に仕方がありませんが。

linkchecker

宣伝になって恐縮ですが、拙作の linkchecker も同様のツールです。コマンドラインで動作しますので、CI に組み込むこともできます。

ウェブサービス型

フォームに URL を入力するとリンクをチェックしてくれるウェブサービスがあります。W3C Link Checker などが代表的です。

ウェブサービス側からアクセスできなければならないため、必然的にチェック対象は本番環境になり、ステージング環境やローカル環境は対象外になってしまいます。

リンク先のページを再帰的にリンクチェックしてくれますが、再帰深さが制限される場合もあります。

実質的にクローリングを行うわけですので、アクセス間隔は適切に取られます。結果的にサイト全体をチェックするのにかなりの時間がかかります。

ウェブサーバ動作型

実際にウェブサーバを動作させてチェックを行う方法です。ウェブアプリもチェック可能ですし、開発環境やステージング環境などの閉じた環境でもチェック可能です。もちろん本番環境に対してチェックを行うこともできます。

CUIから実行できるリンクチェッカーの比較 では2つのリンクチェッカが紹介されていますし、wgetでWebサイトのリンク切れをチェック では wget コマンドを使う方法が紹介されています。Windows や macOS 上で動作する GUI アプリもあります。

動的生成に対する対応

静的解析型、ウェブサービス型、ウェブサーバ動作型のいずれにも言えることですが、JavaScript で動的に生成されるリンクや動的処理によるページ遷移への対応は困難です。究極的にはリンクチェッカ側で JavaScript を動作させるしかないわけで、Selenium でテストスクリプトを書くなどの対応が考えられます。

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

ブロック要素とインライン要素

ブロック要素の幅は親要素の幅一杯に広がる。
インライン要素の幅はコンテンツ幅に依存する。
インライン要素の中にブロックレベル要素を配置することはできない。

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

静的サイトでサイトマップ/RSSを生成する

あおやぎのさいと2.0という個人サイトを HTML 手打ちの静的サイトで運営しています。静的サイトであってもサイトマップとか RSS とかは出力したいのですが、さすがにそれらまで手打ちで作っていたら面倒でしょうがない。ということで、こんな簡単スクリプトを作って生成しています。

mksitemap.pl
#!/usr/bin/env perl

use strict;
use warnings;

use POSIX 'strftime';

print <<'XML';
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
XML

foreach my $file (`find . -name "*.html"`) {
  chomp $file;
  $file =~ s!^\./!!;
  my @stat = stat($file);
  my $lastmod = strftime( "%Y-%m-%d", localtime($stat[9]));
  print <<"XML";
<url>
  <loc>https://www.saoyagi2.net/${file}</loc>
  <lastmod>${lastmod}</lastmod>
</url>
XML
}

print <<'XML';
</urlset>
XML
mkrss.pl
#!/usr/bin/env perl

use strict;
use warnings;

use Encode;
use utf8;

print encode('utf-8', <<"RSS"
<?xml version="1.0" encoding="UTF-8"?>
<rss version='2.0'>
<channel>
<title>あおやぎのさいと2.0</title>
<link>https://www.saoyagi2.net/</link>
<description>あおやぎ(saoyagi2)の個人サイトです。</description>
RSS
);

my @items;
foreach my $file (`find . -name "*.html"`) {
  chomp $file;
  $file =~ s!^\./!!;

  my $buffer = decode('utf-8', `cat $file`);

  next if(!($buffer =~ /<meta name="date" content="(.*)">/));
  my $date = $1;
  next if(!($buffer =~ /<title>(.*)<\/title>/));
  my $title = $1;
  next if(!($buffer =~ /<article>(.+?)<nav>.+?<\/nav>.+?<\/article>/s));
  my $description = $1;
  $description =~ s/<.+?>//sg;
  $description = substr($description, 0, 100);

  push(@items, [$file, $title, $description, $date]);
}
@items = (reverse sort {$a->[3] cmp $b->[3]} @items);
splice @items, 10;

foreach my $item (@items) {
  print encode('utf-8', <<"RSS"
<item>
<title>${$item}[1]<\/title>
<link>https://www.saoyagi2.net/${$item}[0]<\/link>
<description>${$item}[2]<\/description>
<pubDate>${$item}[3]<\/pubDate>
<\/item>
RSS
);
}

print encode('utf-8', <<"RSS"
</channel>
</rss>
RSS
);

文字列連結で XML 組み立てたりしてるいい加減なものですがね。

RSS 生成時の記事作成年月日は各記事に <meta name="date" content="YYYY-MM-DD"> と入れておいて、それを拾うようにしています。

最終的には AWS S3 + AWS CloudFront 環境へ以下のスクリプトでデプロイ。

#!/bin/sh
./mksitemap.pl > sitemap.xml
./mkrss.pl > rss.xml
aws s3 sync . s3://www.saoyagi2.net/ --delete
aws cloudfront create-invalidation --distribution-id xxx --paths '/*'
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

aタグで作ったボタンでPOST送信する

はじめに

PHPのフォームで値を送信する際、aタグで作ったボタンでも送信する方法です。
自分が実装する際に困った箇所もまとめます。

なぜaタグで送信する必要があったか

・inputタグ(type="submit")ではデザイン通りに実装できなかったため。
・formの外のボタンはaタグで実装されており、サイト・システム全体でボタンのスタイルや挙動を統一したかったため。

ソースコード

名前メールアドレスを送信するフォームを例に。
index.phpでフォームの値を送信してフォーム上に値を表示させてみます。

form.php
<?php
if ( isset( $_POST[ "name" ] ) ) {
  $name = htmlspecialchars( $_POST[ "name" ], ENT_QUOTES, "utf-8" );
  echo $name;
}
if ( isset( $_POST[ "email" ] ) ) {
  $email = htmlspecialchars( $_POST[ "email" ], ENT_QUOTES, "utf-8" );
  echo $email;
}
?>
<!-- input[type="submit"]で送信-->
<form method="POST" name="register" action="index.php">
  <input type="text" name="name" value="">
  <input type="text" name="mail" value="">
  <input type="submit" value="送信する">
</form>

<!-- aタグで送信する-->
<form method="POST" name="register" action="index.php">
  <input type="text" name="name" value="">
  <input type="text" name="mail" value="">
  <a href="#" onclick="document.register.submit();">登録する</a>
</form>

説明

・aタグにonclickでformのnameを指定してsubmitイベントを実行させる。

注意点

・同ファイルで同時に表示されているformのnameが同じの場合、formのが正しく動いてくれない。(値が送信できない)

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