LoginSignup
2
1

More than 1 year has passed since last update.

MarinDeck(TweetDeck)で画像のサムネのアスペクト比を元画像通りにするカスタムCSS, jsを書いた

Last updated at Posted at 2022-04-27

事の発端

私の友人にMarinDeckを勧めたら下の画像のように聞かれた

まあ、確かにそうやね
私も結構MarinDeckを使ってて不便だなとは思ってたからこの際解決しようということでカスタムCSS, jsを書いた


MairnDeckを知らない人は下のリンク先を見るなりググるなりしてね

大変なことが発覚した(2022/4/28 00:03追記)

Android版のMarinDeckには「Display images in the original aspect ratio」の項目があって、この記事でできるようになることは公式に設定が可能なのでAndroidをお使いの方々はそっちを使うのがいいと思います

私みたいにiPadで使ってるぜって方々はこの記事が役に立つかも?

やったこと

取り敢えず調査

先の画像にあった「TweetDeckではサムネの縦長表示ができる」というのは多分「Better TweetDeckによってできる」ということなのでGithubからBetter TweetDeckのソースコードを読んだり、実際にブラウザ拡張機能を入れて開発者モードでCSSを見たりしてどうやって実現してるのかを確認した

ざっと見たところ以下のCSSが書かれていることがわかった

.media-size-medium.btd-aspect-ratio-thumbnail, .media-size-large.btd-aspect-ratio-thumbnail {
    height: 0 !important;
    padding-top: min(var(--btd-max-og-ratio-height), calc(var(--btd-thumb-height) / var(--btd-thumb-width) * 100%));
}

画像の高さを0にしてpadding-topで画像表示領域を確保しているらしい
--btd-max-og-ratio-heightは最大の高さで、--btd-thumb-height, --btd-thumb-widthはそれぞれ画像の縦と横の大きさでそれらを使って元画像と同じアスペクト比で幅いっぱいに広げてるらしい

jsの方は以下のようになっていた(一部抜粋)

quotedMediaNode.classList.add('btd-aspect-ratio-thumbnail');
quotedMediaNode.style.setProperty('--btd-thumb-height', quotedSizeObject.height.toString());
quotedMediaNode.style.setProperty('--btd-thumb-width', quotedSizeObject.width.toString());

どうやら画像に対して上のCSSを適用するようにclassを追加して、上で上げた画像の縦横の大きさパラメータをスタイルシートとして渡しているらしい

まあ、同じような動作をするように書けば動くでしょう

カスタムCSSを書く

カスタムCSSは以下のようにした

.aspect-ratio {
  height: 0 !important;
  padding-top: min(50vh, calc(var(--thumb-height) / var(--thumb-width) * var(--media-width)));
}

やってることはBetter TweetDeckのCSSと同じ
(クラス名とかの命名がダサいのは気にしないでください)

カスタムjsを書く

カスタムjsは以下のようにした


const aspect = () => {
    const mediaItems = document.getElementsByClassName('js-media-image-link');
    for (const mediaItem of mediaItems) {
        const imageURL = mediaItem.style.getPropertyValue('background-image').replace(/^url\(["']?/, '').replace(/["']?\)$/, '');
        const image = new Image()
        image.src = imageURL;

        if(mediaItem.childElementCount == 0) {
            mediaItem.classList.add('aspect-ratio');
            mediaItem.style.setProperty('--thumb-height', image.naturalHeight);
            mediaItem.style.setProperty('--thumb-width', image.naturalWidth);
            mediaItem.style.setProperty('--media-width', mediaItem.clientWidth + 'px');

            // 複数画像のときは圧縮しないで全部縦に並べる
            if (mediaItem.classList.contains('media-image')) {
                mediaItem.classList.remove('pin-all');
                mediaItem.parentElement.classList.remove('position-rel');
                mediaItem.style.setProperty('border-radius', '14px');
                mediaItem.parentElement.style.setProperty('margin-bottom', '8px');
                mediaItem.parentElement.parentElement.classList.remove('media-grid-2', 'media-grid-3', 'media-grid-4');
                mediaItem.parentElement.parentElement.parentElement.style.setProperty('height', 'auto', 'important');
            }
        }else {
            mediaItem.classList.remove('aspect-ratio');
        }
    }
}

const body = document.body;
const observer = new MutationObserver(() => {
    aspect()
});
const config = {
    childList: true,
    attributes: false,
    characterData: false,
    subtree: true
}
observer.observe(body, config);
aspect();

2022/4/28 00:03追記

ツイート単体を表示した際に画像が見えない状態になったので修正

2022/4/28 09:44追記

複数の画像を含んだツイートでも全ての画像が大きく表示されるようにした


こっちもやってることはBetter TweetDeckと同じだけどところどころ解説していく

const imageURL = mediaItem.style.getPropertyValue('background-image').replace(/^url\(["']?/, '').replace(/["']?\)$/, '');
const image = new Image()
image.src = imageURL;

サムネ画像はbackground-imageに設定されているっぽいので正規表現を使ってURLの文字列を取り出して、画像オブジェクトとして持つ

if(mediaItem.childElementCount == 0) {
     mediaItem.classList.add('aspect-ratio');
     mediaItem.style.setProperty('--thumb-height', image.naturalHeight);
     mediaItem.style.setProperty('--thumb-width', image.naturalWidth);
}else {
    mediaItem.classList.remove('aspect-ratio');
}

ここでやってるのはBetter TweetDeckと全く同じ
クラスを付与して先に取得した画像オブジェクトから縦横の大きさを取得してスタイルで保持

2022/4/28 00:03追記
ツイート単体を表示しているときはmedia-itemのクラスを持つタグのbackground-imageではなくそのタグの子要素としてimgタグが画像を表示しているため、子要素が存在する場合はaspect-ratioクラスを剥奪して画像がちゃんと表示されるようにした

2022/4/28 09:43追記
複数の画像付きツイートの場合は圧縮表示を無効化して全て大きく表示するようにした


const body = document.body;
const observer = new MutationObserver(() => {
    aspect()
});
const config = {
    childList: true,
    attributes: false,
    characterData: false,
    subtree: true
}
observer.observe(body, config);
aspect();

あとはオブザーバーでbody全体を子要素も含めて監視させて変化があったとき(新たなツイートが流れてきたときとか)に上で書いた処理をやらせる

MarinDeckに適用

あとはMarinDeckの設定からカスタムCSS, jsをそれぞれ入力してリロードすれば完成

おわりに

  • MarinDeckはスマホ・タブレットでTweetDeckが使える素晴らしいアプリ
  • ただ、カスタムCSS, jsの書き方というかリファレンスみたいなやつを出してくれるとありがたい(これをMarinDeckに対して言うのは違う気がする)
  • Android版には公式でこの機能はあるからAndroid版を使ってる人たちはアプリの設定からこれを使ったほうが楽(MarinDeckのテーマを作ってる人の引用リツイートで気づいた)
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1