Designing for Different Devices (Touch & Hover)

This document outlines the APIs used to adapt Discourse’s user interface for different devices.

Touch & Hover

Some devices only have touchscreens, some only have a traditional mouse pointer, and some have both. Importantly, touchscreen users cannot “hover” over elements. Therefore, interfaces should be designed to work entirely without hover states, with hover-specific enhancements added for devices that support them.

There are several ways to detect touch/hover capability via CSS and JavaScript. For consistency, we recommend using Discourse’s helpers instead of those CSS/JS APIs directly.

For CSS, you can target the .discourse-touch and .discourse-no-touch classes, which are added to the <html> element. These are determined based on the (any-pointer: coarse) media query.

For example:

html.discourse-touch {
  // SCSS rules here will apply to devices with a touch screen,
  // including mobiles/tablets and laptops/desktops with touch screens.
}

html.discourse-no-touch {
  // SCSS rules here will apply to devices with no touch screen.
}

This information is also available in Ember components via the capabilities service:

import Component from "@glimmer/component";
import { service } from "@ember/service";

class MyComponent extends Component {
  @service capabilities;

  <template>
    {{#if this.capabilities.touch}}
      This text will be displayed for devices with a touch screen
    {{/if}}

    {{#unless this.capabilities.touch}}
      This text will be displayed for devices with no touch screen
    {{/unless}}
  </template>
}

Legacy Mobile / Desktop Modes

Historically, Discourse shipped two completely different layouts and stylesheets for “mobile” and “desktop” views, based on the browser’s user-agent. Developers would target these modes by putting CSS in specific mobile/desktop directories, by using the .mobile-view/.desktop-view HTML classes, and the site.mobileView boolean in JavaScript.

These techniques are now considered deprecated and should be replaced with the viewport and capability-based strategies discussed in the next document. For backwards-compatibility, legacy desktop/mobile CSS is used when the viewport is larger/smaller than the sm threshold.

See also


This document is version controlled - suggest changes on github.

「いいね!」 13

これは非推奨になるということですか?

@service site;
...
const mobileView = this.site.mobileView;

静的なコンテキストで行う場合、はい、それは今後の「ビューポートベースのモバイルモード」(現在は無効)と互換性がなくなります。

次のような自動追跡コンテキストでチェックを行う場合:

@service site;
...

<template>
  {{#if this.site.mobileView}}
    ...
  {{/if}}
</template>

Ember は、モバイルビューのブール値が変更されたとき(つまり、ブラウザのサイズが変更されたとき)に自動的に再レンダリングします。したがって、問題ありません。

確認のためですが、getterに入れるのは非推奨ですが、<template> に入れないのは非推奨ではないということですか?

Emberによって自動追跡されるため、ゲッターに入れることも問題ありません。

@service site;

get shouldRender(){
  return this.site.mobileView;
}

<template>
  {{#if this.shouldRender}}
    ...
  {{/if}}
</template>

^^ これは問題ありません

悪い例は次のようになります。

export default apiInitializer((api) => {
  if(api.container.lookup("service:site").mobileView){
    api.renderInOutlet("some-outlet", <template>My content</template>)
  }
});

この状況では、mobileViewはアプリケーションの起動時にのみチェックされるためです。ブラウザをリサイズしても、イニシャライザは再実行されません。

そのため、次のようにリファクタリングします。

export default apiInitializer((api) => {
  const site = api.container.lookup("service:site");
  api.renderInOutlet("some-outlet", <template>
    {{#if site.mobileView}}My content{{/if}}
  </template>);
});

これにより、ブラウザのリサイズ時にmobileViewの変更が有効になります。

「いいね!」 3

承知いたしました。説明ありがとうございます!

「いいね!」 1

(投稿は作者によって削除されました)

「いいね!」 1

一般的な推奨事項は次のとおりです。そのようなことはしないでください。なぜそのような経験が画面サイズによって異なる必要があるのでしょうか?

便利な思考実験は次のとおりです。折りたたみ式電話やタブレットではどのように動作すると予想されますか?これらは明示的にモバイル/デスクトップのバケットに収まりません。

ユーザーエージェントに基づいてこのような動作変更を行いたい場合は(古いモバイル/デスクトップモードが機能したように)、capabilities.isMobileDevice があります。これは、ユーザーエージェント文字列に「mobile」という単語が含まれているかどうかを文字通りチェックします。

「いいね!」 1

私の場合は、デスクトップでホームページをタグの交差ルートに切り替えるオプションを提供しているためです。そのインターフェースはモバイルには存在しません…(ただし、ルートは実際に機能します - 追加のコントロールは非表示になっています)

…しかし、ご指摘はもっともです。おそらく考え直します!

「いいね!」 1

面白い!それが意図的なのかどうか疑問に思います…どのデバイスでも機能するはずだと思います :thinking:

「いいね!」 2

ということは、Discourse は pull-left を非推奨にするということですか?あのクラスは扱うのが少々厄介なので、なくなってくれると嬉しいのですが。

それは本当に嬉しいですね :wink:

解決策はメッセージ内にあります

コンポーネントを条件付きで含めるのではなく、常に含め、コンポーネント自体に条件付きでレンダリングさせます。

「いいね!」 1

お気持ちはわかりますが、このコンポーネントは私が所有しているものではなく、コアの一部であり、特定のルートに含まれています。コア側でこれをモバイルとデスクトップの両方で動作するようにするのが最善の解決策です。

現状では、このページをホームページ(グローバルに)に設定することはできますが、モバイルでは動作しないため意味がありません。

これを現在完全に活用されておらず、少し厄介な別の例として挙げます。カテゴリーページです。デスクトップでは現状のままで構いませんが、モバイルではカテゴリーパネルを非表示にしてトピックリストのみを残すことで「最新」ページに変更することを検討してください。なぜなら、モバイルでカテゴリービューのみでトピックリストがないのは、私見では最悪だからです。

しかし、その場合、モバイルではこれは「カテゴリー」ページではなくなります。

これは、デバイスを初期化時に識別できなくなったため、モバイルホームページのテーマコンポーネントが機能しなくなったという事実によって、さらに悪化しています。

したがって、相互運用性と利用デバイスへの適合性のために、ディスカバールート(discovery routes)を何らかの形で再考する必要があると考えています。

「いいね!」 2