Switch to logical properties to handle LTR/RTL at once
Prerequisites
- [X] I have searched for duplicate or closed feature requests
- [X] I have read the contributing guidelines
Proposal
Referring to this comment and this SO answer, and CanIUse inset-inline-end and others, it seems these following properties are supported in all major browsers (or green?) since mid 2020
inset-inline-start (in place of left property) inset-inline-end (in place of right property) margin-inline-start (in place of margin-left property) margin-inline-end (in place of margin-right property) margin-inline (in place of margin shorthand property) padding-inline-start (in place of padding-left property) padding-inline-end (in place of padding-right property) padding-inline (in place of padding shorthand property) text-align: start; (in place of left value) text-align: end; (in place of right value) float: inline-start; (in place of left value) float: inline-end; (in place of right value)
following styles are still using left and right
me-0 ... 'me-auto',
ms-0 ... ms-auto,
.start ... .start-100
.end ... end-100
however using above mentioned attribute and properties will allow easier transition between LTR and RTL
so instead of
LTR .start-0 { left: 0 !important; }
RTL .start-0 { right: 0 !important; }
We can have just
.start-0 { inset-inline-start: 0 !important; }
and so on.
Currently I'm testing these transitions with following html, which allows me immediate transition between RTL and LTR
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<link rel="stylesheet" href="bootstrap-5.3.0/bootstrap.css">
<link rel="stylesheet" href="this/main.css">
<script src="jquery.1.11.3/jquery.min.js"></script>
<script src="bootstrap-5.3.0/bootstrap.bundle.js"></script>
<script>
$(function () {
const $html = $('html');
if (localStorage.getItem('dir') === 'rtl') {
$html.attr('dir', 'rtl');
} else {
$html.removeAttr('dir')
}
$('#btnDir').click(function () {
if ($html.attr('dir') === 'rtl') {
$html.removeAttr('dir');
localStorage.removeItem('dir')
} else {
$html.attr('dir', 'rtl');
localStorage.setItem('dir', 'rtl')
}
});
})
</script>
</head>
<body>
<input type="button" id="btnDir" class="btn btn-primary" value=" direction ">
<!-- Elements being tested below-->
<div class="toast-container p-3 bottom-0 end-0" aria-live="polite" aria-atomic="true">
<div class="toast show text-bg-danger" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="me-auto">Toast-Header</strong>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body">Toast Body</div>
</div>
<div class="toast text-bg-danger border-0 show" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body">
Hello, world! This is a toast message.
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
<div class="toast text-bg-primary border-0 show" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body">Toast Body</div>
<button type="button" class="btn-close btn-close-white m-auto ms-auto me-2" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
</div>
</body>
</html>
Content of main.css is something like following (obviously for these to work I need to comment their counter part in bootstrap.css)
.text-start{ text-align:start !important; }
.text-end{ text-align:end !important; }
.me-0{ margin-inline-end:0 !important }
.me-1{ margin-inline-end:0.25rem !important }
.me-2{ margin-inline-end:0.5rem !important }
.me-3{ margin-inline-end:1rem !important }
.me-4{ margin-inline-end:1.5rem !important }
.me-5{ margin-inline-end:3rem !important }
.me-auto{ margin-inline-end:auto !important }
.start-0{ inset-inline-start:0 !important; }
.start-50{ inset-inline-start:50% !important;}
.start-100{ inset-inline-start:100% !important;}
.end-0{ inset-inline-end:0 !important; }
.end-50{ inset-inline-end:50% !important;}
.end-100{ inset-inline-end:100% !important;}
.toast-header .btn-close {
margin-inline-end: calc(-0.5 * var(--bs-toast-padding-x));
margin-inline-start: var(--bs-toast-padding-x);
}
Motivation and context
I think it allows transition from having two separate CSS for LTR and RTL to one single file. and in case in future you want to support top to bottom languages ;)
This has been considered 3 years ago while implementing RTL for v5 (see #30918). Support was still short at that time, but switching to logical properties should be one of the main move coming in V6.
I'm tagging this for v6 as I noticed there's currently no dedicated issue!
Or what would have made more sense is keep the selector and change the property, so while in LTR, design for LTR, and it will magically flip on RTL
text-left { text-align: start}
text-right {text-align: end}
I really expected (hoped) for this, don't know why you went for the extreme of renaming selectors, but keeping the properties
text-start {text-align: left}
why?
@ffoodd is this still something the team is open to changing for v6? I don't see it listed in #41380
At this point, CSS Logical Properties have been supported in all major browsers in Baseline since September 2021, so it should be overwhelmingly supported:
https://caniuse.com/css-logical-props
Removing the RTLCSS dependency would streamline our dependencies.
IMHO, I'd say yes ! For now, @mdo started to work on v6 with specific topics but I think logical properties are the way to go.