うぃろぅ.log

140字で綴りきれない日々の徒然備忘録

わけのわからないHTMLを読む

うぃろぅです。
納期1に追われてしばらく死んでいました。多分今月は状況が変わりそうにありません。
上司に「これ修正したんですけど反映していいですかー」と訊くたびに「ちょっと待ってね」と返ってきて下手に動けないため今回遭遇した事象を書きます。

若干長くなったので目次置いときます。

今日のお題

久しぶりにとんでもないHTMLを見た

何があったの

今何をやっているかというお話。とあるandroid / iOS向けの交通系アプリを改修しているのですが、このアプリの追加機能として、「お知らせタブを選択したらWebViewでサーバに置いてあるHTMLを表示」というものがあります。
アプリの中でサイトのお知らせがみられる、みたいなあれですな。

アプリ側の開発は私のチームが対応していて、表示するHTMLは別チームのおじさんが作成している、という体制です。
このおじさんがまぁ仕事ができないらしく、お客様からもクレームが来るという方なのですが、詳細は置いておきましょう。

で、先日「android6.0だとHTML内のリンク(target="_blank")を叩いてもブラウザ起動してくれない、WebView内で開いてしまうから前の画面に戻れない」という報告を受けたので解析をしました。
最終的に「アプリ側でブラウザを起動して対応」という形にしたのですが、これが最適解ではない気がするので答えを探したいところ(手が回ってない)。

この修正をする過程で上記のおじさんが作成したHTMLを見てみたわけなのですが、ついつい笑ってしまったためここで供養しておきます。

件のHTML

※ 名前等いろいろ伏せていますが構造的にはほとんど変えていません

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<head>

<title>HogeView</title>

<meta name="viewport"
        content="initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<style type="text/css">
.fsize {
        font-size: 75%;
}

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

<script type="text/javascript">
        var agent = navigator.userAgent;
        
        // タイトル設定
        function setTitle(_title) {
               if (agent.search(/Mac OS/) != -1) {
                              document.location="iphone://setTitle?title=" + _title;
               } else if (agent.search(/Android/) != -1) {
                              android.setTitle(_title);
               }
        }

        // リロード
        function reloadWebView() {
               if (agent.search(/Mac OS/) != -1) {
                              document.location="iphone://reloadWebView";
               } else if (agent.search(/Android/) != -1) {
                              android.reloadWebView();
               }
        }

        // 外部アプリ起動(例:Hogeアプリ)
        function startApp() {
               if (agent.search(/Mac OS/) != -1) {
                              document.location="iphone://startApp?&siteUrl=hoge://&storeUrl=https://example.com";
               } else if (agent.search(/Android/) != -1) {
                              android.startApp("hoge://","https://example.com")
               } else {
                              window.open('https://example.com', '_blank');
               }
        }
</script>
</head>
<body class="fsize">
<!-- 表形式:2列。アイコン表示:罫線なし -->
<table width="100%" border="0">
<caption></caption>
<thead></thead>
<colgroup col span="2">
<!-- 1列目の幅 -->
<col width="200">
<!-- 2列目の幅 -->
<col width="200">
</colgroup>

<tbody>

<tr>
<!-- WEBページ起動 別ウィンドウ表示 ほげほげ -->
<td valign="top">
<figure style="text-align:center;"id="HgHgInf">
<a href="https://example.com" target="_blank">
<img src="images/hoge_logo.png" alt="Hoge Hoge Information" width="60" height="60" hspace="0" valign="top">
</a>
<figcaption>Hoge Hoge Information</figcaption>
</figure>
</td>

<!-- WEBページ起動 別ウィンドウ表示 ふがふが -->
<td valign="top">
<figure style="text-align:center;"id="FugaInf">
<a href="https://example.net" target="_blank">
<img src="images/fuga_logo.png" alt="Fuga Info" width="60" height="60" hspace="0" align="top">
</a>
<figcaption>Fuga Info</figcaption>
</figure>
</td>
</tr>

<tr>
<!-- アプリ紹介ページ 別ウィンドウ表示 ~ほげふが紹介ページ~ -->
<td valign="top">
<figure style="text-align:center;"id="HogeFuga">
<a href="javascript:void(0)" onclick="startApp();">
    <img src="images/hogefuga_ico.png" alt="HogeFuga" width="60" height="60" hspace="0" valign="top">
</a><br>
    <img src="images/hogefuga_logo.png" alt="HogeFuga" width="87" height="20" hspace="0" valign="top">
</figure>
</td>

<!-- WEBページ起動 別ウィンドウ表示 ~ふーばー~ -->
<td valign="top">
<figure style="text-align:center;"id="fooBar">
<a href="https://example.org" target="_blank">
<img src="images/foobar_logo.jpg" alt="Foo Bar Organization" width="90" height="40" hspace="0" valign="top">
</a>
<figcaption>Foo Bar Organization</figcaption>
</figure>
</td>

</body>
</html>

賢明なる皆様は普段こんなHTMLを読むことはないでしょうが、本当にこんな感じでした。

f:id:vviilloovv:20200214143843p:plain

ブラウザで表示するとこんな感じ。画像ファイルは置いてません。
さて、順番に見ていきましょう。

問題点を見てみよう

タグの重複

5行目あたりなんですが、

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<head>

headタグが重複しています。なぜ。
このheadタグ、ここで閉じるべきなのかというとそうではなく、54行目でちゃんと閉じタグがあるんですよね。
なので単純ミスなのかな、という気がします。なぜ。

謎のCSSファイル読み込み

17行目に<link rel="stylesheet" href="Hoge_sample.css" type="text/css">とありますね。
どうやらHoge_sample.cssというCSSファイルを読み込んでいるようです。なのでファイルサーバを確認してみました。
そんなファイルは存在しませんでした。まぁそんなこったろうと思ったよ。_sampleの箇所は名称変更してないし。
おそらくその辺に転がっていたHTMLサンプルをコピペしてきたのでしょう。よくある話ですね。

タグが閉じていない

そもそもこのファイルをIDEで開いたらエラーが出たんですよ。「エレメントが閉じられていない」みたいなエラー文言。
そうなんです。</body>の周辺を見ていただけたらなんとなくわかるかもしれません2が、trタグとtbodyタグとtableタグが閉じられていません。

根本原因が見えてきましたね。

調べてみたらtbodyの閉じタグは省略可能のようです。 詳しくは後述。

valign間違い探し

CSSを読み込んでいないのでHTML内にstyle要素を直書きしているため、割と多くの箇所にvalign="top"が記載されているのですが、84行目に注目すると、<img src="images/fuga_logo.png" alt="Fuga Info" width="60" height="60" hspace="0" align="top">となっており、ここだけvalignalignになっています。サイゼリヤかよ。

コピペ漏れでしょうか。もしかしたら意図してこうしているのかもしれませんが、その場合topは指定しても意味がないんですよね。

ここまでは「絶対おかしい」と指摘できるポイント。ここからは「いやまぁいいけどさぁ」なポイントです。
※ 個人の感想です。

インデント

一番気になるのはここですよね。headbodyがインデントなしなのは人によりけりなので気になりませんが、せめてtable配下は字下げしたいですね。左の壁に粘着テープでも貼ってあるんか???

大方ページのソースを表示でHTMLが自動生成されているサイトをコピペしたのではなかろうかと推測されますが、試しにはてなブログ(この画面)のソースを表示してみても

  <div class="curation-header header">
    <h2>
      編集サイドバー
    </h2>
    <p>よく使う機能は、ショートカットとしてタブに追加できます。</p>
  </div>

ちゃんとインデントされているんですよね。うーん。

空のタグ

58行目あたりなのですが、

<caption></caption>
<thead></thead>

中身がないタグがあるんですよね。これは省略可能な気がしますが、どうなんでしょうか。
試しに省略してみても問題なく表示はできましたが記載するお作法なのでしょうか…?

コメント内に謎の例示

43行目あたりに// 外部アプリ起動(例:Hogeアプリ)とあります。
この例は何なんでしょうか。HTML内にはこのメソッドを呼び出している箇所が1か所しかないんですよね。追加する方針でもあるのかしら…?

大きさの単位が不明

結構いろいろな箇所にwidth="60" height="60"という表記があります。きっと単位はpxなのでしょう。emだと大変なことになりそうですし。でも単位を書かないってどうなのでしょうね。line-heightに記載しないのはよく見るのですが。
ちなみに私は中学生くらいの頃に図形の問題で単位が書かれていないのにcmだったかを入れて不正解をもらったことがあります。許せん(自業自得)。

列のグループ化の意図が不明

60行目あたりの

<colgroup col span="2">
<!-- 1列目の幅 -->
<col width="200">
<!-- 2列目の幅 -->
<col width="200">
</colgroup>

ここなんですが、これを記載する意図が分からないんですよね。これって

ID 名前 生年月日
1 花澤香菜 1989年2月25日
2 小倉唯 1995年8月15日
3 豊崎愛生 1986年10月28日

こんな感じで列の幅が違うことを明示的に示すために利用すると考えています。
でも上記のソースだとこの幅が同じなんですよね。明示的に同じ幅にしたかったのかもしれない。なあにこれえ。

謎のID付与

随所に見られるid="HgHgInf"のようなIDはいつ使うのでしょうか。CSSでもJavaScriptでも使用している形跡がみられないんですよね。必要性が気になるところ。

もっというとC言語の変数名のような謎の省略がされていたり、1文字目が大文字になっていたり小文字になっていたりと統一性もない。CSSで指定するならclass指定がよく見るのですがなんなんでしょうか。私今日ずっと混乱してるな。

こんなところでしょうか…?探せばもっとあるかも??私には何もわからないよ。

どうしたか

  • HTMLを全体的に修正
  • CSSを分離

上記2点を修正してそのファイルを使ってくれないかと懇願しました。
現在は「ちょっと待ってね」状態なので通るといいなあ、といったところ。

修正後を貼っておきます。多分これでもまだまだだと思うのでマサカリ大歓迎。
CodePenは会社のWebフィルターでブロックされてしまうので貼れませんでした。かなしい。

  • HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>HogeView</title>
  <meta name="viewport" content="initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
    var agent = navigator.userAgent;
        
    // タイトル設定
    function setTitle(_title) {
      if (agent.search(/Mac OS/) != -1) {
        document.location="iphone://setTitle?title=" + _title;
      } else if (agent.search(/Android/) != -1) {
        android.setTitle(_title);
      }
    }

    // リロード
    function reloadWebView() {
      if (agent.search(/Mac OS/) != -1) {
        document.location="iphone://reloadWebView";
      } else if (agent.search(/Android/) != -1) {
        android.reloadWebView();
      }
    }

    // 外部アプリ起動
    function startApp() {
      if (agent.search(/Mac OS/) != -1) {
        document.location="iphone://startApp?&siteUrl=hoge://&storeUrl=https://example.com";
      } else if (agent.search(/Android/) != -1) {
        android.startApp("hoge://","https://example.com")
      } else {
        window.open('https://example.com', '_blank');
      }
    }
  </script>
  <link href="https://unpkg.com/sanitize.css" rel="stylesheet" />
  <link rel="stylesheet" href="links.css" type="text/css" />
</head>

<body>
  <table>
    <tbody>
      <tr>
        <!-- WEBページ起動 別ウィンドウ表示 ほげほげ -->
        <td>
          <figure>
            <a href="https://example.com" target="_blank" >
              <img class="hoge-info" src="images/hoge_logo.png" alt="Hoge Hoge Information">
            </a>
            <figcaption>Hoge Hoge Information</figcaption>
          </figure>
        </td>
        
        <!-- WEBページ起動 別ウィンドウ表示 ふがふが -->
        <td>
          <figure>
            <a href="https://example.net" target="_blank" >
              <img class="fuga-info" src="images/fuga_logo.png" alt="Fuga Info">
            </a>
            <figcaption>Fuga Info</figcaption>
          </figure>
        </td>
      </tr>
      
      <tr>
        <!-- 外部アプリ紹介ページ 別ウィンドウ表示 ~ほげふが紹介ページ~ -->
        <td>
          <figure>
            <a href="javascript:void(0)" onclick="startApp();">
              <img class="hogefuga-icon" src="images/hogefuga_ico.png" alt="HogeFuga">
            </a><br>
            <img class="hogefuga-logo" src="images/hogefuga_logo.png" alt="HogeFuga">
          </figure>
        </td>
        
        <!-- WEBページ起動 別ウィンドウ表示 ~ふーばー~ -->
        <td>
          <figure>
            <a href="https://example.org" target="_blank">
              <img class="foobar" src="images/foobar_logo.jpg" alt="Foo Bar Organization">
            </a>
            <figcaption>Foo Bar Organization</figcaption>
          </figure>
        </td>
      </tr>
    </tbody>
  </table>
</body>
</html>
body {
  font-size: 75%;
}
td {
  valign: top;
}
table {
  width: 100%;
  border: 0;
}
figure {
  text-align: center;
}
img {
  hspace: 0;
  valign: top;
}
img.hoge-info {
  width: 60px;
  height: 60px;
}
img.fuga-info {
  width: 60px;
  height: 60px;
}
img.hogefuga-icon {
  width: 60px;
  height: 60px;
}
img.hogefuga-logo {
  width: 87px;
  height: 20px;
}
img.foobar {
  width: 90px;
  height: 40px;
}

できるだけ元ソースを維持したまま修正してこんな感じに。
これが正しいかもわからない。私は今霧の中にいる。

どうしてこうなったか

原因は…何なんでしょうね。
割とおじさん自身にある気がしていて、  

  • そもそもの知識不足
  • コピペでこれまで何とかなってきた謎の自信
  • 人に訊けないプライドと年齢

あたりは大きい気がしています。
防ぐ方法としては

  • レビューをする
  • もう少し何とかなりそうなひな型を作っておいて参考にしてもらう

あたりですかね。

あとさっきCSSのタグについて見つけたサイトがあります。

html-coding.co.jp

こちらのサイトの例えばtableタグのページ。

f:id:vviilloovv:20200214174428p:plain

実に「それっぽく」ないですか…?

ちなみに少し下にスクロールするとちゃんとインデントされているサンプルが掲載されています。
サイトは悪くない。

f:id:vviilloovv:20200214175827p:plain

気になるのはこのサイトがHTML5とCSS3に対応していないことですが、それはサイト運営側の話なので私が何か言える立場ではないですね。

今日の教訓

クソコードに気をつけて

結局修正するのは私のような末端になるんですよね。うまいこと受け流して生きていきましょう。
私はこれから別のバグ修正が入ったので終電の心配をしながら作業を続けます。

ではまた。


  1. そもそもが無理めなスケジュール、割と抵抗はした。

  2. そもそも読みたくない? あなたは健全です。