How does the _:-ms-lang(x) fix for Edge and IE work?
Categories:
Understanding the _:-ms-lang(x)
CSS Hack for Edge and IE

Explore how the _:-ms-lang(x)
CSS selector targets Microsoft Edge and Internet Explorer, its historical context, and modern alternatives.
In the world of web development, cross-browser compatibility has always been a significant challenge. Developers often resort to browser-specific hacks to ensure consistent rendering and functionality across different user agents. One such hack, _:-ms-lang(x)
, gained popularity for targeting Microsoft's Internet Explorer and early versions of Edge. This article delves into the mechanics of this selector, its historical relevance, and why it works.
The Anatomy of _:-ms-lang(x)
The _:-ms-lang(x)
selector is a combination of two distinct parts: a prefixed pseudo-class and an invalid element selector. Let's break it down:
_
(Invalid Element Selector): The underscore_
is not a valid HTML element name. According to CSS parsing rules, if a browser encounters an invalid selector, it typically discards the entire rule. However, older versions of Internet Explorer (and by extension, early Edge versions due to its Trident/EdgeHTML heritage) had a quirk in their CSS parser. When they encountered an invalid element selector followed by a valid pseudo-class, they would still attempt to parse and apply the pseudo-class.:-ms-lang(x)
(Microsoft-Specific Pseudo-class): This is a vendor-prefixed pseudo-class specific to Microsoft browsers. The-ms-
prefix indicates it's a Microsoft extension. Thelang()
pseudo-class is generally used to select elements based on their language attribute (e.g.,lang(en)
). However,lang(x)
with an arbitrary, non-standard language code likex
is not a valid or meaningful language identifier. Despite this, IE/Edge would still process the pseudo-class itself.
The combination of these two quirks meant that only IE and Edge would successfully parse and apply styles defined within a _:-ms-lang(x)
rule, while other browsers would discard it due to the invalid _
element selector.
flowchart TD A[Browser Parses CSS Rule: `_:-ms-lang(x)`] --> B{Is `_` a valid HTML element?} B -- No (Standard Browsers) --> C[Discard Rule] B -- No (IE/Edge Quirk) --> D{Is `:-ms-lang(x)` a recognized pseudo-class?} D -- Yes (IE/Edge) --> E[Apply Styles] D -- No (Other Browsers) --> C C --> F[Rule Ignored] E --> G[Styles Applied to Target Elements]
How the _:-ms-lang(x)
selector is processed by different browsers
Practical Application and Evolution
This hack was primarily used to fix layout or rendering issues specific to IE and Edge without affecting other browsers. For instance, if a flexbox layout behaved differently in Edge, developers could use _:-ms-lang(x)
to apply specific adjustments.
Example Usage:
Consider a scenario where a div
element needs a specific margin-top
in IE/Edge to align correctly:
.my-element {
margin-top: 10px; /* Default for all browsers */
}
_:-ms-lang(x), .my-element {
margin-top: 15px; /* Only applied in IE/Edge */
}
In this example, .my-element
would have a margin-top
of 10px
in most browsers, but 15px
in IE/Edge because the _:-ms-lang(x)
selector would successfully apply its rule, overriding the previous one.
With the transition of Microsoft Edge to a Chromium-based browser, this hack is largely obsolete for modern Edge versions. Chromium-based Edge behaves like other modern browsers and will discard the _:-ms-lang(x)
rule. It remains relevant only for legacy Internet Explorer and the original EdgeHTML-based Edge.
/* General styles */
.container {
display: flex;
justify-content: space-between;
padding: 20px;
}
/* IE/Edge-specific fix for flex item spacing */
_:-ms-lang(x), .container > * {
margin-right: 10px; /* Add extra spacing between flex items */
}
_:-ms-lang(x), .container > *:last-child {
margin-right: 0; /* Remove margin from the last item */
}
Example of _:-ms-lang(x)
used to apply IE/Edge-specific flexbox adjustments.
_:-ms-lang(x)
is generally discouraged in modern web development. They often depend on browser quirks that can change or be removed, leading to broken layouts in future browser versions. Prefer feature detection or standard CSS solutions.Modern Alternatives and Best Practices
Instead of relying on obscure hacks, modern web development emphasizes standards-compliant CSS and progressive enhancement. For targeting specific browser behaviors when absolutely necessary, consider these approaches:
Feature Queries (
@supports
): This is the most robust and recommended method. It allows you to apply styles only if a browser supports a specific CSS feature. This is far more reliable than browser sniffing or hacky selectors.Browser-specific CSS files (via JavaScript): While not ideal, you can use JavaScript to detect the browser (e.g., via
navigator.userAgent
) and dynamically load a browser-specific stylesheet. This should be a last resort.Vendor Prefixes (for experimental features): For new or experimental CSS properties, vendor prefixes (like
-webkit-
,-moz-
,-ms-
) are still used, but these are for features, not for general browser targeting.Polyfills: For missing JavaScript or CSS features, polyfills can provide fallback functionality for older browsers.
/* Using feature queries for modern, robust targeting */
@supports (display: grid) {
.grid-layout {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
}
@supports not (display: grid) {
/* Fallback for browsers that don't support CSS Grid */
.grid-layout {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.grid-layout > * {
width: 48%; /* Approx half width for two columns */
}
}
Modern approach using @supports
to provide fallbacks for CSS Grid.