forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			356 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			356 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
| RTL Guidelines
 | ||
| ==============
 | ||
| 
 | ||
| RTL languages such as Arabic, Hebrew, Persian and Urdu are read and
 | ||
| written from right-to-left, and the user interface for these languages
 | ||
| should be mirrored to ensure the content is easy to understand.
 | ||
| 
 | ||
| When a UI is changed from LTR to RTL (or vice-versa), it’s often called
 | ||
| mirroring. An RTL layout is the mirror image of an LTR layout, and it
 | ||
| affects layout, text, and graphics.
 | ||
| 
 | ||
| In RTL, anything that relates to time should be depicted as moving from
 | ||
| right to left. For example, forward points to the left, and backwards
 | ||
| points to the right.
 | ||
| 
 | ||
| Mirroring layout
 | ||
| ~~~~~~~~~~~~~~~~
 | ||
| 
 | ||
| When a UI is mirrored, these changes occur:
 | ||
| 
 | ||
| -  Text fields icons are displayed on the opposite side of a field
 | ||
| -  Navigation buttons are displayed in reverse order
 | ||
| -  Icons that communicate direction, like arrows, are mirrored
 | ||
| -  Text is usually aligned to the right
 | ||
| 
 | ||
| In CSS, while it's possible to apply a rule for LTR and a separate one
 | ||
| specifically for RTL, it's usually better to use CSS `Logical Properties <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties>`_
 | ||
| which provide the ability to control layout through logical, rather than
 | ||
| physical mappings.
 | ||
| 
 | ||
| +---------------------------------------------------------+--------------------------------------------------+
 | ||
| | Do                                                      | Don't do                                         |
 | ||
| +---------------------------------------------------------+--------------------------------------------------+
 | ||
| | ``margin-inline-start: 5px``                            | ``margin-left: 5px``                             |
 | ||
| +---------------------------------------------------------+--------------------------------------------------+
 | ||
| | ``padding-inline-end: 5px``                             | ``padding-right: 5px``                           |
 | ||
| +---------------------------------------------------------+--------------------------------------------------+
 | ||
| | ``float: inline-start``                                 | ``float: left``                                  |
 | ||
| +---------------------------------------------------------+--------------------------------------------------+
 | ||
| | ``inset-inline-start: 5px``                             | ``left: 5px``                                    |
 | ||
| +---------------------------------------------------------+--------------------------------------------------+
 | ||
| | ``border-inline-end: 1px``                              | ``border-right: 1px``                            |
 | ||
| +---------------------------------------------------------+--------------------------------------------------+
 | ||
| | ``border-{start/end}-{start/end}-radius: 2px``          | ``border-{top/bottom}-{left/right}-radius: 2px`` |
 | ||
| +---------------------------------------------------------+--------------------------------------------------+
 | ||
| | ``padding: 1px 2px``                                    | ``padding: 1px 2px 1px 2px``                     |
 | ||
| +---------------------------------------------------------+--------------------------------------------------+
 | ||
| | ``margin-block: 1px 3px`` && ``margin-inline: 4px 2px`` | ``margin: 1px 2px 3px 4px``                      |
 | ||
| +---------------------------------------------------------+--------------------------------------------------+
 | ||
| | ``text-align: start`` or ``text-align: match-parent``   | ``text-align: left``                             |
 | ||
| | (depends on the context)                                |                                                  |
 | ||
| +---------------------------------------------------------+--------------------------------------------------+
 | ||
| 
 | ||
| When there is no special RTL-aware property available, or when
 | ||
| left/right properties must be used specifically for RTL, use the pseudo
 | ||
| ``:-moz-locale-dir(rtl)`` (for XUL documents) or ``:dir(rtl)`` (for HTML
 | ||
| documents).
 | ||
| 
 | ||
| For example, this rule covers LTR to display searchicon.svg 7 pixels
 | ||
| from the left:
 | ||
| 
 | ||
| .. code:: css
 | ||
| 
 | ||
|    .search-box {
 | ||
|      background-image: url(chrome://path/to/searchicon.svg);
 | ||
|      background-position: 7px center;
 | ||
|    }
 | ||
| 
 | ||
| but an additional rule is necessary to cover RTL and place the search
 | ||
| icon on the right:
 | ||
| 
 | ||
| .. code:: css
 | ||
| 
 | ||
|    .search-box:dir(rtl) {
 | ||
|      background-position-x: right 7px;
 | ||
|    }
 | ||
| 
 | ||
| .. warning::
 | ||
| 
 | ||
|    It may be inappropriate to use logical properties when embedding LTR
 | ||
|    within RTL contexts. This is described further in the document.
 | ||
| 
 | ||
| Mirroring elements
 | ||
| ~~~~~~~~~~~~~~~~~~
 | ||
| 
 | ||
| RTL content also affects the direction in which some icons and images
 | ||
| are displayed, particularly those depicting a sequence of events.
 | ||
| 
 | ||
| What to mirror
 | ||
| ^^^^^^^^^^^^^^
 | ||
| 
 | ||
| -  Icons or animations that imply directionality or motion like
 | ||
|    back/forward buttons or progress bars
 | ||
| -  Icons that imply text direction, like
 | ||
|    `reader-mode.svg <https://searchfox.org/mozilla-central/rev/f9beb753a84aa297713d1565dcd0c5e3c66e4174/browser/themes/shared/icons/reader-mode.svg>`__
 | ||
| -  Icons that imply location of UI elements in the screen, like
 | ||
|    `sidebars-right.svg <https://searchfox.org/mozilla-central/rev/74cc0f4dce444fe0757e2a6b8307d19e4d0e0212/browser/themes/shared/icons/sidebars-right.svg>`__,
 | ||
|    `open-in-new.svg <https://searchfox.org/mozilla-central/rev/f9beb753a84aa297713d1565dcd0c5e3c66e4174/toolkit/themes/shared/icons/open-in-new.svg>`__,
 | ||
|    `default theme's preview.svg <https://searchfox.org/mozilla-central/rev/f9beb753a84aa297713d1565dcd0c5e3c66e4174/toolkit/mozapps/extensions/default-theme/preview.svg>`__
 | ||
|    or
 | ||
|    `pane-collapse.svg <https://searchfox.org/mozilla-central/rev/74cc0f4dce444fe0757e2a6b8307d19e4d0e0212/devtools/client/debugger/images/pane-collapse.svg>`__
 | ||
| -  Icons representing objects that are meant to be handheld should look
 | ||
|    like they're being right-handed, like the `magnifying glass
 | ||
|    icon <https://searchfox.org/mozilla-central/rev/e7c61f4a68b974d5fecd216dc7407b631a24eb8f/toolkit/themes/windows/global/icons/search-textbox.svg>`__
 | ||
| -  Twisties in their collapsed state. Note that if the context in which
 | ||
|    they appear is LTR (e.g. code in a devtools HTML view), they should
 | ||
|    not be mirrored, even if the user might be using an RTL locale.
 | ||
| 
 | ||
| What NOT to mirror
 | ||
| ^^^^^^^^^^^^^^^^^^
 | ||
| 
 | ||
| -  Text/numbers
 | ||
| -  Icons containing text/numbers
 | ||
| -  Icons/animations that are direction neutral
 | ||
| -  Icons that wouldn't look differently if they'd be mirrored, like `X
 | ||
|    buttons <https://searchfox.org/mozilla-central/rev/a78233c11a6baf2c308fbed17eb16c6e57b6a2ac/devtools/client/debugger/images/close.svg>`__
 | ||
|    or the `bookmark
 | ||
|    star <https://searchfox.org/mozilla-central/rev/a78233c11a6baf2c308fbed17eb16c6e57b6a2ac/browser/themes/shared/icons/bookmark-hollow.svg>`__
 | ||
|    icon, or any other symmetric icon
 | ||
| -  Icons that should look the same as LTR, like icons related to code
 | ||
|    (which is always LTR) like
 | ||
|    `tool-webconsole.svg <https://searchfox.org/mozilla-central/rev/74cc0f4dce444fe0757e2a6b8307d19e4d0e0212/devtools/client/themes/images/tool-webconsole.svg>`__
 | ||
| -  Checkmark icons
 | ||
| -  Video/audio player controls
 | ||
| -  Product logos
 | ||
| -  Order of size dimensions (e.g., ``1920x1080`` should not become
 | ||
|    ``1080x1920``)
 | ||
| -  Order of size units (e.g., ``10 px`` should not become ``px 10``
 | ||
|    (unless the size unit is localizable))
 | ||
| 
 | ||
| How
 | ||
| ^^^
 | ||
| 
 | ||
| The most common way to mirror images is by flipping the X axis:
 | ||
| 
 | ||
| .. code:: css
 | ||
| 
 | ||
|    transform: scaleX(-1);
 | ||
| 
 | ||
| Or, if you're already using ``transform`` with a different value on the same
 | ||
| element, you can also use `scale`:
 | ||
| 
 | ||
| .. code:: css
 | ||
| 
 | ||
|    scale: -1 1;
 | ||
| 
 | ||
| Note that mirroring images that way doesn't work when the image is a part of
 | ||
| an element with text using ``background-image``, because then the text would
 | ||
| be mirrored along with the image, and the image would be positioned incorrectly.
 | ||
| For such cases, try to use a different method for displaying the image,
 | ||
| like having it as an element all on its own.
 | ||
| If that's not possible, add a separate pre-mirrored image asset and specify
 | ||
| it in a separate ``:dir(rtl)`` rule:
 | ||
| 
 | ||
| .. code:: css
 | ||
| 
 | ||
|    .element-with-icon {
 | ||
|      background-image: url("path/to/image/image.svg");
 | ||
|    }
 | ||
| 
 | ||
|    .element-with-icon:dir(rtl) {
 | ||
|      background-image: url("path/to/image/image-rtl.svg");
 | ||
|    }
 | ||
| 
 | ||
| For animations like a progress bar, when using ``@keyframes`` to change
 | ||
| the ``transform: translateX()`` states, make sure to add a different
 | ||
| ``@keyframes`` suited for RTL, and target that in a separate ``:dir()`` rule:
 | ||
| 
 | ||
| .. code:: css
 | ||
| 
 | ||
|    #progressbar {
 | ||
|      animation: progressbar-animation 1s linear infinite;
 | ||
|    }
 | ||
| 
 | ||
|    #progressbar:dir(rtl) {
 | ||
|      animation-name: progressbar-animation-rtl;
 | ||
|    }
 | ||
| 
 | ||
|    @keyframes progressbar-animation {
 | ||
|      0% {
 | ||
|        transform: translateX(-100px);
 | ||
|      }
 | ||
|      100% {
 | ||
|        transform: translateX(0);
 | ||
|      }
 | ||
|    }
 | ||
| 
 | ||
|    @keyframes progressbar-animation-rtl {
 | ||
|      0% {
 | ||
|        transform: translateX(100px);
 | ||
|      }
 | ||
|      100% {
 | ||
|        transform: translateX(0);
 | ||
|      }
 | ||
|    }
 | ||
| 
 | ||
| Likewise, if you're using ``transform-origin``, make sure to specify the
 | ||
| correct origin for RTL:
 | ||
| 
 | ||
| .. code:: css
 | ||
| 
 | ||
|    #progressbar {
 | ||
|      transform-origin: 0 0;
 | ||
|    }
 | ||
| 
 | ||
|    #progressbar:dir(rtl) {
 | ||
|      transform-origin: 100% 0;
 | ||
|    }
 | ||
| 
 | ||
| LTR text inside RTL contexts
 | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | ||
| 
 | ||
| By default, in RTL locales, some symbols like ``/`` and ``.`` will be moved
 | ||
| around and won't be displayed in the order that they were typed in. This
 | ||
| may be problematic for URLs for instance, where you don't want dots to
 | ||
| change position.
 | ||
| 
 | ||
| Here's a non-exhaustive list of elements that should be displayed like
 | ||
| they would be in LTR locales:
 | ||
| 
 | ||
| -  Paths (e.g., C:\\Users\\username\\Desktop)
 | ||
| -  Full URLs
 | ||
| -  Code and code containers (like the DevTools' Inspector or the CSS
 | ||
|    rules panel)
 | ||
| -  about:config preference names and values
 | ||
| -  Telephone numbers
 | ||
| -  Usernames & passwords (most sites on the web expect LTR
 | ||
|    usernames/passwords, but there may be exceptions)
 | ||
| -  Other text fields where only LTR text is expected
 | ||
| 
 | ||
| To make sure these are displayed correctly, you can use one of the
 | ||
| following on the relevant element:
 | ||
| 
 | ||
| -  ``direction: ltr``
 | ||
| -  ``dir="ltr"`` in HTML
 | ||
| 
 | ||
| Since the direction of such elements is forced to LTR, the text will
 | ||
| also be aligned to the left, which is undesirable from an UI
 | ||
| perspective, given that is inconsistent with the rest of the RTL UI
 | ||
| which has text usually aligned to the right. You can fix this using
 | ||
| ``text-align: match-parent``. In the following screenshot, both text
 | ||
| fields (username and password) and the URL have their direction set to
 | ||
| LTR (to display text correctly), but the text itself is aligned to the
 | ||
| right for consistency with the rest of the UI:
 | ||
| 
 | ||
| .. image:: about-logins-rtl.png
 | ||
|    :alt: about:logins textboxes in RTL layout
 | ||
| 
 | ||
| However, since the direction in LTR, this also means that the start/end
 | ||
| properties will correspond to left/right respectively, which is probably
 | ||
| not what you expect. This means you have to use extra rules instead of
 | ||
| using logical properties.
 | ||
| 
 | ||
| Here's a full code example:
 | ||
| 
 | ||
| .. code:: css
 | ||
| 
 | ||
|    .url {
 | ||
|      direction: ltr; /* Force text direction to be LTR */
 | ||
| 
 | ||
|      /* `start` (the default value) will correspond to `left`,
 | ||
|       * so we match the parent's direction in order to align the text to the right */
 | ||
|      text-align: match-parent;
 | ||
|    }
 | ||
| 
 | ||
|    /* :dir(ltr/rtl) isn't meaningful on .url, since it has direction: ltr, hence
 | ||
|     * why it is matched on .container. */
 | ||
|    .container:dir(ltr) .url {
 | ||
|      padding-left: 1em;
 | ||
|    }
 | ||
| 
 | ||
|    .container:dir(rtl) .url {
 | ||
|      padding-right: 1em;
 | ||
|    }
 | ||
| 
 | ||
| .. note::
 | ||
| 
 | ||
|    The LTR rule is separate from the global rule to avoid having the
 | ||
|    left padding apply on RTL without having to reset it in the RTL rule.
 | ||
| 
 | ||
| Auto-directionality
 | ||
| ^^^^^^^^^^^^^^^^^^^
 | ||
| 
 | ||
| Sometimes, the text direction on an element should vary dynamically
 | ||
| depending on the situation. This can be the case for a search input for
 | ||
| instance, a user may input a query in an LTR language, but may also
 | ||
| input a query in a RTL language. In this case, the search input has to
 | ||
| dynamically pick the correct directionality based on the first word, in
 | ||
| order to display the query text correctly. The typical way to do this is
 | ||
| to use ``dir="auto"`` in HTML. It is essential that
 | ||
| ``text-align: match-parent`` is set, to avoid having the text alignment
 | ||
| change based on the query, and logical properties also cannot be used on
 | ||
| the element itself given they can change meaning depending on the query.
 | ||
| 
 | ||
| Testing
 | ||
| ~~~~~~~
 | ||
| 
 | ||
| To test for RTL layouts in Firefox, you can go to about:config and
 | ||
| set ``intl.l10n.pseudo`` to ``bidi``, or select the ``Enable "bidi" locale``
 | ||
| option in the 3-dots menu in the :doc:`Browser Toolbox </devtools-user/browser_toolbox/index>`.
 | ||
| The Firefox UI should immediately flip, but a restart may be required
 | ||
| to take effect in some Firefox features and interactions.
 | ||
| 
 | ||
| .. note::
 | ||
| 
 | ||
|    When testing with ``intl.l10n.pseudo`` set to ``bidi``, you may see some
 | ||
|    oddities regarding text ordering due to the nature of displaying LTR
 | ||
|    text in RTL layout.
 | ||
| 
 | ||
|    .. image:: about-protections-rtl.png
 | ||
|       :alt: about:protections in RTL layout- English vs. Hebrew
 | ||
| 
 | ||
|    This shouldn't be an issue when using an actual RTL build or language pack.
 | ||
| 
 | ||
| How to spot RTL-related issues
 | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | ||
| 
 | ||
| -  Punctuation marks should appear on the left side of a
 | ||
|    word/sentence/paragraph on RTL, so if a *localizable* string appears
 | ||
|    in the UI with a dot, colon, ellipsis, question or exclamation mark
 | ||
|    on the right side of the text, this probably means that the text
 | ||
|    field is forced to be displayed as LTR.
 | ||
| -  If icons/images/checkmarks do not appear on the opposite side of
 | ||
|    text, when compared to LTR.
 | ||
| -  If buttons (like the close button, "OK" and "Cancel" etc.) do not
 | ||
|    appear on the opposite side of the UI and not in the opposite order,
 | ||
|    when compared to LTR.
 | ||
| -  If paddings/margins/borders are not the same from the opposite side,
 | ||
|    when compared to LTR.
 | ||
| -  Although Hebrew uses ``1 2 3``, all the other RTL locales we support
 | ||
|    should use ``١ ٢ ٣`` as digits. So if you see ``1 2 3`` on any such
 | ||
|    locale, that likely indicates a bug.
 | ||
| -  If navigating in the UI using the left/right arrow keys does not
 | ||
|    select the correct element (i.e., pressing Left selects an item on
 | ||
|    the right).
 | ||
| -  If navigating in the UI using the Tab key does not focus elements
 | ||
|    from right to left, in an RTL context.
 | ||
| -  If code is displayed as RTL (e.g., ``;padding: 20px`` - the semicolon
 | ||
|    should appear on the right side of the code). Code can still be
 | ||
|    aligned to the right if it appears in an RTL context.
 | ||
| 
 | ||
| See also
 | ||
| ~~~~~~~~
 | ||
| 
 | ||
| -  `RTL Best
 | ||
|    Practices <https://docs.google.com/document/d/1Rc8rvwsLI06xArFQouTinSh3wNte9Sqn9KWi1r7xY4Y/edit#heading=h.pw54h41h12ct>`__
 | ||
| -  Building RTL-Aware Web Apps & Websites: `Part
 | ||
|    1 <https://hacks.mozilla.org/2015/09/building-rtl-aware-web-apps-and-websites-part-1/>`__,
 | ||
|    `Part
 | ||
|    2 <https://hacks.mozilla.org/2015/10/building-rtl-aware-web-apps-websites-part-2/>`__
 | ||
| 
 | ||
| Credits
 | ||
| ~~~~~~~
 | ||
| 
 | ||
| Google's `Material Design guide for
 | ||
| RTL <https://material.io/design/usability/bidirectionality.html>`__
 | 
