| @技術/プログラミング

外出自粛かつ自分自身にコロ助疑惑があったのでずっと部屋に閉じこもってサイトのデザインをいじってた。

2020-04-07 デザインアップデート.jpg

左がこれまでで、真ん中が今後、右が画像がワイドな場合のバージョン。これまで横幅 1280px 想定にして画像も横幅 1280px のサイズで表示するようにしていた。

ただしこれだと写真は見やすくても文字が読みにくい。人間の目は 1280px 繰り返し左右に移動させるのには適していないようだった( N=1 )。

そういうわけでまたまた cho45 さんのブログのレイアウトをパクって、文章は横幅短めに、写真はでかいサイズで表示するようにした。

文章部分の幅を 800px にして、画像を読み込んだときに一定の条件にマッチしたら写真の横幅を 1280px で表示するようにした。 margin-left: -250px; してるのがミソ。横幅 800px だと大分文章は読みやすいし、でかい写真は大きく見えて便利。

@media screen and (min-width: 1422px) {
  #content #main article .body > p {
    img[class~="large"] {
      width: $content-max-width;
      max-width: $content-max-width;
      margin-left: -250px;
    }
  }
}

JS はこんな感じのコードを書いた。

const checkImageSize = (target) => {
  if (typeof target === 'undefined') {
    return;
  }
  const width = target.naturalWidth;
  const height = target.naturalHeight;
  const isPhoto = RegExp('(lh3\.googleusercontent\.com|\.jpe?g$)').test(target.src);
  if (width > 1279 && width > height && isPhoto) {
    target.classList.add('large');
  }
}

const lazyImageObserver = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const lazyImage = entry.target;
      lazyImage.src = lazyImage.dataset.src;
      lazyImage.addEventListener('load', (event) => checkImageSize(event.target));
      lazyImageObserver.unobserve(lazyImage);
    }
  });
});

const selectors = "#content article .body img, #content article .similar img";
const lazyImages = [].slice.call(document.querySelectorAll(selectors));

if ("IntersectionObserver" in window) {
  for (let image of lazyImages) {
    const src = image.src;
    image.dataset.src = src;
    if (lazyImages.indexOf(image) === 0) {
      const promise = new Promise(resolve => resolve(image));
      promise.then(checkImageSize).catch(setTimeout(checkImageSize, 100))
      continue;
    }
    image.src = "";
  };

  lazyImages.forEach(lazyImage => {
    lazyImageObserver.observe(lazyImage);
  });
}

画像の読み込みが起こったタイミングにフックして画像のサイズチェックを行い、条件にマッチしたら img タグに class を追加し、 CSS のメディアクエリと合わせ技で大きく表示するようにしている。以前やった画像の遅延読み込みのコードを改良した。

その他、 HTML 5 対応が中途半端だったのでマークアップを見直して、適度に <header><secition><article><footer> を使ってマークアップし直した。 このせいだと思うけど Google Adsense の自動広告が差し込まれる位置が変わった。これまでヘッダーの下に入り込んでいたやつが <header><article> の間に入るようになった。

今後も外出禁止が続いたらひたすら自分のブログをいじってしまう予感。こういうエネルギーを仕事とか個人サービス開発とかに当てられるとよいのだろうけどなかなかそういう方向には向かない。

| @ブログ

noisy-ads.jpg

スマートフォンで検索していてある大手ブログサービスでホストされているブログの記事に辿り着いた。記事を読んでいくと、ページ構造が「パーマリンクとは?」という感じになっていて驚いた。まるで蟻地獄で、下にスクロールしても終わりがなく、一度入り込んだら逃げられない感じだった。一つの URL に一つのコンテンツというインターネットのお約束を無視していて、 URL は個別記事のものだけど、下までスクロールすると次の記事の本文が読み込まれる。さらにスクロールするとそのまた次の記事が読み込まれる。 AutoPagerize がページャーのないところでも有効化されている感じで、読者の好みで無効化できない状態になっていた。

記事と記事の間には芸能ニュース記事へのリンクが差し込まれたり、そのブログサービス内で人気の記事ランキングが挟まれたりする。 A さんのブログを読んでいたはずなのに気がつくとゴシップニュースか他の人の炎上記事を読むことになっている。おまけにそこに広告も挟まれてくる。ページ内で URL が指し示すオリジナル記事の分量が 10% に満たないこともあるんじゃないだろうか。書き手にとっても読み手にとっても体験が良くない。大手のブログサービスはどこも同じような感じで、他のニュース記事や人気記事への誘導が激しい。

Twitter を追い出されたあとの Evan Williams が Medium を始めたときは意味がわからなかった。今時ブログサービスなんて始めてどうするんだろうと思った。はてなブログに関しても、なぜいま新しいブログサービスが必要なのかわからなかった。しかしいまならその理由がわかる気がする。

インターネット上でのコミュニケーションの場がブロゴスフィア(死語)から SNS へ移り、ブログの読者は SNS を流し読みしていてタイムラインに流れてきたコンテンツを消化するだけ。著者はコンテンツを提供するだけの存在となってしまい、両者の間でインタラクティブなやりとりが生まれなくなった。そんな状況でもう一度著者と読み手を中心に据えようとして始まったのが Medium だったのではないだろうか。

Medium もはてなブログも広告は表示されないか表示されても少しだし、 Medium の人気記事への誘導は控えめで、はてなブログは同一ブログ内の記事しかお勧めしてこない。

はてなブログを開始されて間もないときに jkondo が書いている記事の最後にこんなフレーズが出てくる。

「個」としての活動が、人生に新しい展開を持ち込み、より豊かな人生につながります。

SNS 、ブログ、あらゆるところで巨大なサービス(=プラットフォーム)が幅を効かせて個人を飲み込もうとしているいま、どこでブログを書くと一番記事の価値を毀損しないかまで考えてブログを書く場所を選んだ方がよいと思う。はてなブログや Medium 、 note も流行ってるっぽいが、自分としてはやっぱり自分のブログを持つのが最高だと思ってる。

独立自営のブログをやる人の選択肢を増やすために、今後も Lokka のメンテナンスはやっていきたい。やりたい・やると宣言して出来てないことだらけで申し訳ないけど、少しずつこのブログの機能を master ブランチに移植していって 2020 年でも常用できるブログにしていきたい。ちなみに以下は Markdown をオン・ザ・フライでプレビューする機能の Pull Request 。

あと Slack に Workspace を作った。何年か前に調べたときは lokka.slack.com が空いてたんだけど誰かに取られてたので lokkahq.slack.com となった。良かったら入ってください。ちなみにまだ僕しかいません。

追記 2020-04-13

cho45 さんの昔のブログ記事を読んでたらわかる(わかる)という記事があったのでリンクしておきます。

ノウハウ蓄積みたいなコンテンツってASP型で預けるのは不安がありすぎるので、自力で配信しようねみたいなウェブ縄文時代みたいな話になるんですが……

CGMサービスの矜持について - 氾濫原

ウェブ縄文時代 ってのは言い得て妙だと思いました。残念だけど一周回って個人ウェブサイトは縄文時代を迎えつつあるんだと思う。

| @ブログ

最近、やたらこのブログにスパムコメントが来るようになった。コメントがあったらメールで通知されるようにしてるのだけど、コメント通知メールが一日十件くらい届く。

スパムコメント

Google の reCAPTCHA を入れたことでほぼほぼスパムコメントは弾けていたのだけど、最近のスパムは reCAPTCHA をすり抜けるようになってしまったっぽい。加えて Akismet のスパム判定ロジックもポンコツになってしまったようで、ほぼほぼすべてのコメントをスパムと判定しなくなってしまった。

Lokka では Akismet でスパム判定されたコメントは一括削除できるようになっている(この機能は自分で作った)が、スパム判定されなかったコメントはちまちま一つずつ削除しなければならないのが非常に煩わしかった。

なのでコメント一覧にチェックボックスを表示して、チェックを入れたコメントを一括で削除できるようにしてみた。めっちゃ便利。

コメント一括削除

Akismet プラグインも少し改造して、自分で NG ワードを設定できるようにした。最近のスパムは露骨に Viagra とか Cialis みたいなキーワードが入ってて、どうしてこんなわかりやすいやつを Akismet は素通りさせてしまうのかわからないのだけど、自前の NG ワードフィルターで二重にチェックするようにした。

NG ワード

最後にアクセスログからスパムっぽいコメントの数を集計して管理画面のダッシュボードで閲覧できるようにした。引き続き監視していきたい。

スパムの状況

| @労働

COVID-19.jpg

Basecamp の Jason Fried が Amazon で REMOTE がバカ売れし始めたので返金を始めたそう。なぜ返金するのかというと、本が売れているのは多くの人がリモートワークを恐れており、そのような恐怖・不安に REMOTE という本が役立つから、とのこと。

アメリカはリモートワーク先進国なのかなと思っていたけど、やっぱり昔ながらの方法で仕事してた会社もあったんだろう。アメリカでもコロナウイルスが猛威を振るいつつあるいま、そのような会社もリモートワークをやるようになり、リモートワークの心構えが書いてある本がバカ売れしてるということですね。おもしろい。

HashiCorp の Mitchell Hashimoto さんのリモートワークについてのツイートもおもしろかった。これまでのリモートワーク経験で得られたことが書かれている。

全従業員をリモートワークに、という動きは良い傾向だと思うが、たくさんの不安・疑念・不信を引き起こす。多くの人が「はいはいこんなもんね」という感じで仕事をするだろうが、リモートワークは一筋縄ではいかない。多くの人が仕事に使う机を会社のものから自宅の自分のものに置き換えただけのことではないな、ということに気がつくだろう。

リモートワークは一部の人にとってはうまく機能しない。みんながリモートワークに適応できるわけではなく、それは仕方がないことだ。これまで HashiCorp ではたくさんの人が「仕事は楽しい、同僚も好きだ、ただやっぱり自分は顔をつきあわせたコミュニケーションの方がいい」という理由で会社を去って行った。これは自然なことだ。

このほかにも Hashimoto さんが新しく従業員を雇ったときに説明するリモートワークについての心構えが書かれていてうなずきながら読んだ。一番最初のやつから結構ショッキングだが事実だと思う。

「君は友だちができない」。残酷だが事実だ。リモートワークをするなら、仕事以外でとても仲の良い友だちがいないとダメだ。なぜなら仕事では友だちができないから。リモートワークでも同僚とは仲良くなれる。でもリモートワークの同僚とは遊びに行ったり、子ども同士が同じ学校になる、ということはない。

そのほかのツイートもおもしろいので読んでみて下さい。

2020-03-14 追記

Jason Fried が元の Tweet を消してしまっている。およそ 400 件の返金請求が来たみたい。自動化できておらず破滅状態なので返金は終了するとのこと。

| @ブログ

Rubbish

ブログで使ってる Amazon S3 のバケットの画像のほとんどをミスって空ファイルにしてしまった…。 S3 に上がっている画像、 Cache-Control ヘッダーが付与されていないのですべての画像ファイルに Cache-Control ヘッダーを付与しようとしての事故だった。ファイル一覧を取得して AWS SDK Ruby で Cache-Control だけ付与するつもりだったのにファイルそのものを空で上書きしてしまって無となった。

大した操作じゃないと思って事前にバックアップを取っていなかった& S3 に上げておけば安心だと思って日常のバックアップも行っていなかった。スーパーアホ。写真ならアップロードし直すことは可能だけど、キャプチャとか、アニメーション Gif とか、ブログの内容に合わせて OmniGraffle で描いた画像は基本的には元のファイルが残ってなくて元に戻すことができなかった…。

CDN に残っていたものとローカルでキャッシュされていたものを探したが、 500 ファイル以上が失われてしまった。つらい…。

画像の吹っ飛び、過去にも何回か起こっている。レンタルサーバーの障害で消えたパターンもあったけど、自分のミスで消してしまうパターンが多い。自分が一番信用ならないので画像はプロに管理してもらうのが一番だなと身にしみて思った…。とりあえず S3 バケットのバージョンコントロールを有効にしたいと思います…

追記

AWS SDK Ruby での正しい Cache-Control ヘッダー付与の仕方は以下だった。

 object.copy_from(object, cache_control: 'max-age=2592000,s-maxage=31536000', metadata_directive: "REPLACE")

#copy_from の引数に medata_directive: "REPLACE" を渡す必要がある。

🙅🏻‍♀️🙅🏻‍♀️🙅🏻‍♀️以下は NG なので注意されたし ☠️☠️☠️

 object.put(cache_control: 'max-age=2592000,s-maxage=31536000')

これやるとファイルの body が空になります 🈳🈳🈳