Consider this code (also in a fiddle):
document.getElementById("span").innerHTML += $('#input').css('fontSize');
span input {
font-size: inherit;
}
input {
font-size: 15px;
}
<span id="span" style="font-size: 30px;">
<input id="input"/>
</span>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
In Chrome and Firefox, the .css('fontSize') will return 30px, in Edge and IE it's 15px. Why does it do that? The DOM Explorer in Edge even shows the 15px in strikethrough, and therefore should take the inherited 30px as the fontSize:
And the input is rendered with a 30px font, so IE/Edge is picking it up for rendering purposes.
Update: The bug below is now fixed; FremyCompany says he/she is a program manager from the Edge team and the fix will reach customers in early 2017.
It looks very much like an IE and Edge bug. Not having found it, I reported it.
Here's an update to the snippet that sees what IE/Edge is telling jQuery via getComputedStyle or currentStyle:
var input = $("#input");
console.log("jQuery: " + input.css('fontSize'));
if (window.getComputedStyle) {
console.log("getComputedStyle: " + getComputedStyle(input[0]).fontSize);
}
if (input[0].currentStyle) {
console.log("currentStyle: " + input[0].currentStyle.fontSize);
}
span input {
font-size: inherit;
}
input {
font-size: 15px;
}
<span id="span" style="font-size: 30px;">
<input id="input"/>
<span id="size"></span>
</span>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
For me, IE11 returns 15px from both getComputedStyle and the Microsoft-specific currentStyle property (it's reassuring that they do at least say the same thing):
So it's not a jQuery bug, it's a Microsoft bug when reporting the size via JavaScript (looks like when inherit is the governing rule), even though it's rendering it correctly.
I tried to find a way to make this a grey area, but couldn't think of anything. For instance, according to the spec, having an input inside a span is entirely valid.
Before I get to the real answer I'd like to dig a little into details.
What is this piece of code doing?
.css();
In the jQuery Docs they tell us:
Get the value of a computed style property for the first element in
the set of matched elements or set one or more CSS properties for
every matched element.
Furthermore:
The .css() method is a convenient way to get a computed style property
from the first matched element, especially in light of the different
ways browsers access most of those properties (...)
So what does computed mean?
MDN Docs:
the computed value of a CSS property is computed from the specified
value by:
Handling the special values inherit and initial, and
Doing the computation needed to reach the value described in the "Computed value" line in the property's summary
Ok, now that part is clear too. Let's get to the real answer:
According to Specifics on CSS Specificity there are css-rules with more 'weight' than others have on an HTML element.
Here is the actual order:
Style Attribute
ID
Class, Pseudo Class Attributes
Element
According to that rules your input should've taken the inherited 30px from the Style attribute.
So what is happening in IE11/Edge?
IE11 and Edge are both computing the CSS Rules wrong. If you change your CSS into only this:
span input {
font-size: inherit;
}
It is starting to work. With the information gathered I am assuming that the JavaScript - Engine of both is computing the real CSS value instead of following the CSS rules order.
I've tried to either change the ID and putting a class on the input but still no luck.
I can remember that IE11 and Edge had some problems with inherited CSS and pseudo classes, maybe it is related to that?
Regards,
Megajin
Related
I have created a modal component in Angular. In a unit test, the modal is appearing in the DOM as shown:
However, I start out with a style on app-modal2 that includes display:none, so what actually renders is just the fixed text above the modal -- the content of the modal is correctly omitted:
When the user takes an action that adjusts the style to include display:block then the content of the modal correctly appears. Which is to say, the code is working exactly as I expect.
What I am confounded about is a unit test.
So: why my title ("Consternation on testing non-inherited-yet-inherited CSS display property") ?
Well, according to the docs, the display property is NOT inherited:
Using browser dev tools, I have confirmed that is true: descendant elements have values other than none for the display property. So even though descendant elements are affected by an ancestor having display: none it is because the subtree rooted at the ancestor is removed -- and this is not considered inheritance. Well, OK, potayto, potahto... Not technically inherited, but acts like it.
The visibility of my modal is controlled by the display property. It is set either to display: none or display:block depending on user actions. But that is strictly dealing with visibility, not existence. That is, #myContent is present with either display value. Since I therefore cannot test for existence of #myContent I must test strictly for visibility.
So how do I check an element for visibility controlled by some ancestor's display value, since display is not inherited? Is there a way to check for any ancestor having display:none? Or is there some other way to do this?
You can try using the jQuery parent() method, and put the style as the first argument.
I found out pretty disturbing your question. I think is one of the most hard questions to answer because goes right to the core of cascading and inheritance.
As far as I could find, display property is the only property that can't be specified (but computed) on how should be display by UA. HTML tags are pre-defined styles, those styles are display on UA without any CSS file, e.g. p elements are display as inline.
I tested it too with devtools; forgetting JS at all for very front-end purposes. (Maybe I'll check with with JS later as -second part-). This answer is intended for all audiences, newbies and experienced devs.
Before declare what is going to be styled, we may note that we have dependencies from the browser (User Agent) that parses the stylesheet.
We do not define all universe of properties to be styled, so when is not defined, a property needs to be set and the user agent roles to set a property (doesn't have to be its initial value), there's no official specification on how UA must render websites, it's expected them to be display as the stylesheet specifies, which often, does not act likely according browsing experience.
Cascading
One of the fundamental design principles of CSS is cascading.
What does an User Agent (UA) cascades? Elements? Properties? Objects?
Well, UA treat HTML tags as elements, and those elements are called as box tree, as the same, text included inside an element are called as text node.
Since CSS syntax and its parsing is a perfect cascade, that is the only word that remains if we need to figure out about how (UA) must display HTML documents. The UA also applies its own style sheet. This means that rendering also depends on the way (units) we use to specify values, if we specify a lot of different values e.g. pixels, cm, percentages, relative units (em, rem), etc, the more information UA needs to parse to be displayed, that's why front-end developers should be encouraged to perform clean css styles with homogeneous units to squeeze every milisecond out of browsing perfomance (such important in mobile experiences).
Inheritance
When no declarations try to set a the value for an element/property
combination. In this case, a value is be found by way of inheritance
or by looking at the property’s initial value.
What is called for inheritance, it's just the css properties that can be inherited (those are already established).
So, if a css property seems to be inherited, it's not really inheritance behavior, it's cascading behavior, and it's inheritance becomes by the nature of the syntax for the specified css property.
Answer
The display property is not inherited, but when none property is set, all the descendants elements will no generate any box-model subtree nor text node, (JS could be forcing the element to be display for testing purposes).
In the case of display:none; when the box tree and text node descendants are hidden by the parent element, the style applied of none is by cascading, not by inheritance.
In the example below, the span that is descendant of the fourth div element has set the background property as inherit, but the background can't be inherited, that's why the span element does not display any color background. Otherwise, the span that is descendant of the third div element inherits the color property. The fourth div element has display set: inline; once again, display can't be inherited, that's why the span element does not inherit that property and is displayed as block by the UA.
*{
border: 1px solid black;
}
.one {
display:block;
}
.two {
}
.three{
background:cornsilk;
}
.childthree{
color:red;
}
span{
background: inherit;
position: relative;
top:80px;
border: 5px solid black;
padding: 5px;
margin:5px;
}
.four{
display:inline;
}
canvas{
background:#99e6ff;
}
html {
padding:1em;
}
<div class="wrapper">
<div class="one">one</div>
<div class="two">two</div>
<div class="three">three
<div class="childthree">I'm a subtree inside the third div<br><span>I'm span tag</span></div>
</div>
<div class="four">four<p>i'm a p tag with thext content<span>I'm a span element inside a p element</span></p</p>
<canvas></canvas>
</div>
I'd like to give broken/errored images some extra CSS:
img:error {
max-width: 20px;
max-height: 20px;
}
but that doesn't work. Is there a way with pure CSS to do this? Is there an img pseudo selector for this? Or even better: a dirty hack that works?
I've looked around, but nobody seems to be wondering =)
(Yes, I know JS can do it and I know how; no need to mention it.)
There is no way in CSS specs or drafts, but Firefox has a proprietary selector (pseudo-class) :-moz-broken. Its documentation is very concise and it says “intended for use mainly by theme developers”, but it can be used e.g. as follows:
:-moz-broken { outline: solid red }
:-moz-broken:after { content: " (broken image)" }
Although the documentation says that it “matches elements representing broken image links”, it actually matches broken images (an img element where the src attribute does not refer to an image), whether they are links or not. Presumably, “links” really means “references” here.
CSS 2.1 says: “This specification does not fully define the interaction of :before and :after with replaced elements (such as IMG in HTML). This will be defined in more detail in a future specification.” But Selectors Level 3 (CSS3 Selectors) just says about them: “They are explained in CSS 2.1.” In practice, browsers handle them differently. Oddly enough, Firefox supports :-moz-broken:after but ignores :-moz-broken:before. It does not support either of these pseudo-elements for normal images, but img:after, too, is supported for a broken image (i.e., the specified content appears after the alt attribute value).
For this, you should use the alt attribute, wich shows up if link is broken and you can as well style background of image :
example:
img {
display:inline-block;
vertical-align:top;
min-height:50px;
min-width:300px;
line-height:50px;
text-align:center;
background:
linear-gradient(to bottom,
blue,
orange,
green);
font-size:2em;
box-shadow:inset 0 0 0 3px;
}
These style will be hidden when image is shown.
http://codepen.io/anon/pen/Kxipq
As you can see, we do not check for broken links, but offer alternative , usefull for blind people , searchengines, whatever , and some extra styles finishes it :)
some extra Image alt attribute best practices
<img src="not_found_image.png" onerror='this.style.display = "none"' />
from:
https://www.geeksforgeeks.org/how-to-hide-image-not-found-icon-when-source-image-is-not-found/
NO there is no :error pseudo class. This is a good site for a comprehensive list of what is available:
http://reference.sitepoint.com/css/css3psuedoclasses
July, 2015 EDIT/ADDITION:
(Thank you Rudie)
https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes
No. There is nothing in CSS selectors level 2.1 or level 3 that allows targeting an image like that.
This is close:
<style>
img[data-broken="true"] {
visibility: hidden;
}
</style>
<img src="none.webp" onerror="this.setAttribute('data-broken', 'true')">
Strictly speaking, it sill uses JavaScript. But the JS is self contained in the image HTML code.
If web designer has a full control over the entire code, it is easy to use browser default font - just don't change any font style and you got it.
However if there is not a full control over it and for example there is some font-related style defined on html or body element, or font-related CSS style for * { ... }, then there is a need to redefine font style to not inherit modified styling.
Is there any way, CSS, pure JavaScript or jQuery solution that would allow explicitly set browser default font for specific element?
Unfortunately, there is no simple "initial value" for font-family. It is, as you know, user-agent dependent.
Perhaps the closest you can come is by using a font keyword. font-family:serif; will use whatever the browser considers to be the default serif font. font-family:sans-serif; is the same, for sans-serif.
This is the closest I can suggest, sorry!
Yes. Do
.my-selector {
font: initial;
}
Well, I understand your requirement sounds simple but UNFORTUNATELY this is just a limitation of web technologies. We can not read browser's / system's font using either CSS or jQuery in any way.
The fonts rendered either by browser or system can not be read by web application. It is not designed that way. All we can do is apply font-family:serif or something similar to that.
I tried couple of POC for you but I could not retrieve the browser default settings.
All we can do is create a new ticket in W3C for font-family reset and let's keep hoping that they include something like that in future..
I would still do some digging for you and get back to you if I find something. This definitely is one very important requirement..
I dealt with such situations before but the other way. Just like overriding with the required font.. That's it!
However,
There is an alternative for this. I won't say it is the best way but we can try this :
Prpeare a JavaScript that reads the user agent, something like this..
var setDefaultFont = {
Android: function () {
$('*').css( "font-family", "//FONT USED IN ANDROID BROWSERS" );
},
BlackBerry: function () {
$('*').css( "font-family", "//FONT USED IN BLACKBERRY BROWSERS" );
},
iOS: function () {
$('*').css( "font-family", "//FONT USED IN iOS BROWSERS" );
},
Opera: function () {
$('*').css( "font-family", "//FONT USED IN OPERA BROWSERS" );
},
Windows: function () {
$('*').css( "font-family", "//FONT USED IN WINDOWS BROWSERS" );
}
};
We can be specific to Windows browsers if we need..
I know this is not the best solution but it should work
This has already been answered, but I found a solution that may be helpful:
*, html, body {
font-family: inherit !important;
}
This tells the root elements of the HTML document to inherit their font from the parent. In this case, the parent would be the browser's user agent styles, so your fonts will inherit from the default.
I've been coming across your questions on a somewhat regular basis it seems, and they appear largely theoretical cases. In any case, the others have more or less pointed you in the right direction, but I'm going to sound off just to re-enforce some points.
Explicit Means
There is no existing built-in functionality in Javascript nor CSS to explicitly assign the browser default font. This is outright impossible with the present CSS specification, however, you could, theoretically, utilize Javascript to get the name of the font for explicit use. I will not attempt to write the Javascript code because I predict it would be time consuming to accurately portray, but I will at least try to provide light on how it may be possible. Additionally, I under no circumstances am implying the following idea will work, but I believe it could work.
Conceptual Structure
I'd suggest the following:
Create 5 span nodes as following:
<span style="font-family: monospace;">Monospace Text</span>
<span style="font-family: sans-serif;">Sans-Serif Text</span>
<span style="font-family: serif;">Serif Text</span>
<span style="font-family: fantasy;">Fantasy Text</span>
<span style="font-family: cursive;">Cursive Text</span>
The five generic font families are the browser defaults, however this does not immediately resolve your question because a) it does not give us an explicit font-name that a person is using and b) the default font for a given element is one of these, not all of them.
Pay respect to the words "a person is using"; what the browser would have used by default versus what the user has set the default font to and subsequently sees by default is very different; this is why Rahul Patil's structure would be imperfect, despite I'll admit this was my original assumption and in most cases he would be absolutely correct.
Note
Certain elements default to different generic font families, and are not consistent from browser to browser. Code blocks, for example, are typically rendered as monospace by default. For consistency, you will need to utilize a CSS Reset file.
Use something like this to detect the font:
http://www.lalit.org/lab/javascript-css-font-detect/
This font detection is not ready for what you need out of the box, you need to modify it to parse a list of fonts and match it to the default. This script only shows the theory behind what may work for you; character dimension comparison, as typically all fonts are different in size in height and width, and that difference is easier to detect when the font size is large (hence why it uses 72 pixels).
Caveat
One major caveat I can think of is that this will typically only be able to detect ASCII / Romanized fonts and may not apply to Unicode sets; I'm sure you could modify it, but it may computationally intensive to accurately detect the font. You would likely retain a database of fonts applicable to each language, and you would need a consistent way to detect the language settings for the browser (and not the system); this is not easy, or even possible to my knowledge in a consistent way.
You can obtain an idea of the language settings using the "navigator.language" and "navigator.userLanguage" variables in Javascript, but these, to my knowledge reflect the system language and not the language used by the browser. Server side code would likely be necessary for this to be achieved with any degree of accuracy.
Build a Javascript routine to parse a list of fonts, and compare said fonts against the dimensions of the elements created in Item 1 of this list. You can get a list of fonts necessary to parse by using Flash. I'd suspect a Java applet would be able to do this as well. This may be helpful (JS+Flash):
https://github.com/gabriel/font-detect-js
http://font-detect.s3.amazonaws.com/index.html
This should, theoretically, give you the explicit font name used by the person. You could extend upon this and also get the default generic fonts for each individual element type (e.g. sans-serif, serif, monospace, fantasy and cursive), but I suspect this would be CPU intensive and would be best used with some of type of system level application; e.g. caching the given conditions for a given member, and create the CSS catered to that specific user.
Implicit Means
A number of people suggested some other means, Daniel Lisik in particular highlighted what I may do, with respect that is "serif" declaration is invalid in it's context, since declaring "sans-serif !important" would assign "sans-serif"; you can actually build up using "inherit !important" and make strict font-family changes with the given "font-family !important". For example:
<html>
<head>
<style>
div { font-family: Cursive; }
p { font-family: Inherit !important; }
.serif { font-family: Serif; }
.sans-serif { font-family: Sans-Serif; }
.serif-important { font-family: Serif !important; }
.sans-serif-important { font-family: Sans-Serif !important; }
</style>
</head>
<body>
<div>
Normal Div Text
<p>Default P Text</p>
<p class="serif">Serif</p>
<p class="sans-serif">Sans-Serif</p>
<p class="serif-important ">Important, Serif</p>
<p class="sans-serif-important ">Important, Sans-Serif</p>
</div>
</body>
</html>
"Normal Div Text" would be in "Cursive"
"Default P Text" would be in "Cursive"
"Serif" would be in "Cursive"
"Sans-Serif" would be in "Cursive"
"Important, Serif" would be in "Serif"
"Important, Sans-Serif" would be in "Sans-Serif"
If you need any clarifications, just ask and I'll edit as necessary.
References
http://www.w3.org/TR/CSS21/fonts.html#value-def-generic-family
http://www.w3.org/TR/CSS2/cascade.html#value-def-inherit
Resources
http://www.lalit.org/lab/javascript-css-font-detect/
https://github.com/gabriel/font-detect-js
http://font-detect.s3.amazonaws.com/index.html
Your question isn't very clear. I don't know if I've misunderstood but I will try to help anyway.
If you're really determined to respect the default browser fonts and font sizes set in the browser then this should do the trick:
html, body {
font-size: 100% !important;
}
body {
font-family: serif !important; /* Or sans-serif, monospace or whatever is appropriate. */
}
Then the inheritance should kick in, as long as you don't set font stacks or sizes on everything else.
Bear in mind, the cascade order comes into play here.
This would override all types of stylesheets except for user stylesheets containing !important declarations set on relevant elements. In this particular case, you just need to respect the user's choices.
Personally, I would just write this:
html, body {
font-size: 100%;
}
body {
font-family: serif; /* Or sans-serif, monospace or whatever is appropriate. */
}
Then I would refrain from setting font stacks on everything else simply because, if an user was really determined to have his own way, he's likely to have set !important declarations on the elements that matter to him, like fonts, etc in his own user stylesheet - and this will override a normal author stylesheet (which omits !important declarations).
The others are right, the initial keyword is a viable method as long as you're not worried about IE because, no version of IE supports it.
So I think your best bet is to look for a polyfill of some sort for IE, or create your own. Modernizer might be worth a look or if you want to create your own, there's polyfill.js. I don't know anything about creating polyfills, sorry!
I know it's not a perfect answer (it's 6am and I've been up all night), but I hope it helps you in some way.
P.S. I've just realised you might have been referring to hijacking a browser's settings to set the default font you want set, regardless of how the user has it set up. It would be pointless doing that. In any case, I don't think it would work if an user has his own user stylesheet especially if it has !important declarations set on the font properties.
You can try it in this way:
.element {
font-family: -webkit-body;
font-family: -moz-body
font-family: -o-body
font-family: body
}
And also try the following which is also working fine:
.element {
font-family: none;
}
Are you simply talking about element selectors?
div {
color: red;
}
input {
font-family: sans-serif;
}
As per my understanding, font-family: none; works fine for me in chrome and firefox.
.element {
font-family: none;
}
This code will inherit to default browser font.
Use a generic font-family. The browser will choose which font is "best" for him :)
font-family: serif;
Is it possible to detect CSS support by using Javascript?
For example, is it possible to detect if the browser supports attribute selectors like this?
input[type='text'] { }
Modernizr is designed to detect browser features and may well be able to help in this instance.
http://www.modernizr.com/
This is a bit speculative as I haven't tested it out, but I believe it would be possible via JS to add a style element followed by an element that it has an effect on, and then test the values:
Speculative untested code, may or may not work (jQuery used for brevity):
$('<style type="text/css" id="foo">input[type="text"]{ width: 10px; }</style>').appendTo('head');
$('<input type="text" id="bar">').appendTo('body');
if ($('#bar').width() == 10)
{
//attr selector supported
}
$('#foo, #bar').remove();
document.querySelectorAll("input[type='text']")
But that fails for older browsers, naturally.
Other than that, you could just use the style property to check if a certain CSS property has been applied or not.
input[type='text'] {
background-repeat: no-repeat; /* or any other irrelevant, non-default value */
}
and
if (myInputElem.style.backgroundRepeat == "no-repeat") {
// selector is supported
}
I must be brain dead. I'm having a hell of a time right aligning numbers in a input field.
.number {
text-align: right;
}
<input name="price" type="text" class="number" />
has no effect.
I need to use an input field since I refer to the value in JavaScript and I'm using it both for input and display.
Thanks
It could be that you have a more specific selector that overrides the text-align property of .number
To make your selector more specific, specify the element type...
input.number {
text-align: right;
}
You may have to get even more specific than that, such as...
#formId input.number { }
Yeah - text-align: right should work.
Are you sure there isn't another style or something that's overriding it?
(If you don't have it already, I'd recommend the FireBug plugin for Firefox: right-click the element in question and select "Inspect Element" - that'll tell you every style that's actually being applied, and what's overridden what.)
If you still can't get that class to override styles coming in from elsewhere, you may also want to try
text-align: right !important;