Related
Given any HTML element that is a child of another element and is automatically inheriting a series of CSS attributes: how can you set one (or all) of those attributes to the default value?
Example:
CSS:
.navigation input {
padding: 0;
margin: 0 30em;
}
HTML
<div class="navigation">
Some text: <input type="text" name="one" />
More text: <input type="text" name="two" />
<!-- The next input, I want it to be as browser-default -->
<div class="child">
<input type="text" name="three">
</div>
</div>
Here, by browser-default I mean I want it to look exactly as if no CSS at all was applied to that element.
Here I'm using an input element as an example, but I'm talking about any kind of element. I'm not asking how to set different CSS attributes to that specific element, I'm asking how to reset it to its defaults.
Different elements have different default attributes like padding when they are not set. For example, a button that has a padding of 0 in CSS will wrap its text without any space. You can later set its padding to another value, but how would you set it to the default padding?
Thanks in advance for any comments!
in your case you can use that :
.navigation input {
all: initial;
}
it will revert all attibutes of your input to initial value.
source :
http://www.w3schools.com/cssref/css3_pr_all.asp
CSS 4 CR has a provision for the revert keyword for values. It looks like intended for the exact purpose in the question and might be used like this:
.navigation input {
all: revert;
}
Still its browser support is not very impressive for the time of writing...
If you are saying about the browser defaults than look at CSS reset stylesheets, they are all over the web, those stylesheets reset each elements properties to a standardized value.
Few Examples
Meyer Web
HTML5 Doctor (CSS Reset With HTML5 Elements Included)
If you are saying manual style resets and ignore inheritance, than until now, there's no way to reset the styles completely unless and until you re-declare their values so for example
div {
color: red;
font-family: Arial;
}
div p {
/* Here it will inherit the parents child unless and
until you re specify properties with different values */
}
You cannot set an attribute to the default value, since the defaults are browser-dependent and cannot be referred to in CSS. Cf. to How to set CSS attributes to default values for a specific element (or prevent inheritance)
On the other hand, your example sets padding and margin, which are not inherited. So the question seems to be how to prevent your own CSS rule from applying to some specific element. Then the answer is that you need to modify the selector of the rule so that the specific element does not match it. In your case, this could be done by changing the selector to
.navigation > input
But the more complicated the markup and the style sheet are, the more difficult it becomes to restrict the effects that way.
The QUICK answer is to use the following CSS to revert your select HTML element back to the browsers default UA style sheet, or whatever is set in the body element:
.navigation input {
all:revert;
}
What Are your Trying to Default to?
Every browser by default comes with a default UA style sheet that applies styles to all HTML elements. HTML is unstyled by default. But as you add more styles to your web pages, through selectivity and cascade you write over many of these native default styles. Often that is ok, as you improve upon the browser's styles or alter them to fit your page design.
But know that the browser's default UA style sheet is usually the default. For example, the element "blockquote" is usually interpreted by most browser style sheets with a standard set of CSS formatting values close to the following:
blockquote {
display: block;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 40px;
margin-right: 40px;
}
However, this formatting is not always consistent between browsers. Each browser designs the HTML elements differently. That means each browser's default is not YOUR default or what you would like or expect. You want consistency, right?
To solve that problem, some people have started creating "reset css sheets" with custom values to layer over the browser's default styles and align all the browsers to the same formats. These sheets do this before applying custom CSS on top of that for specific web projects.This creates a "universal custom style" that overrides the browsers default styles, so all your projects, all your web pages, and all versions of browser start out with a base-level look-and-feel.
But there are problems with this.
Bootstrap, the popular 3rd party CSS vendor solution, creates its own "reboot" sheet to reset HTML elements and override the browser's sheets. But these "reset" styles are incomplete, so add more complexity as to what is the default. In doing so, they subjectively assume everyone expects elements to look like they want, which creates a mess in the case of Bootstrap's reboot "blockquote" style shift, which changes default critical margins like so:
From the Bootstrap 4.0 reboot sheet:
blockquote {
margin: 0 0 1rem;/* top, right-left, bottom */
}
This Bootstrap fix that comes in all Bootstrap downloads fails as it strips the critical left-margin formatting that defines blocked quotes in scientific journals and adds one at the bottom. Bad design! In addition, older browsers don't know what "rem" is, so this solution would fail in a wide range of legacy browsers. It isn't just the custom styles in Bootstrap that's the issue. It is the overall CSS design that fails. Too many legacy browsers will fail to accept these Bootstrap proprietary styles, too many elements are missing from their sheets, its extremely difficult to erase them, and its often too difficult to go back to the browser's try default style sheet.
So, now that you understand all the variable involved, how do you manage all this? To try and return to a "default" you really need to understand how best to manage all these CSS systems in a way that is easy, comprehensive, and complete.
A Better Solution
In general, it is always better to consider the browser's default UA style sheet as the default, uncorrupted by any custom CSS you add later to the page. Then, because each browser is different, its best to use a comprehensive "reset" sheet that truly affects all HTML elements and works in a wider range of old and new browsers so it alters everyone's HTML. When done correctly, such sheets layer over the browser's default sheet correctly, but also apply custom CSS to the body element such that when you later use all:revert, the default goes back to the browser's default CSS style sheet, but includes some critical layout and font styles applied in the body element that affect the overall style and which do not get erased in your "reset" sheet.
Why? Because reverting back to defaults also includes whatever text or other inheriting CSS properties you added to the parent body tag. This allows you to not just honor the browser's default styles, but shift all the browser's to use the same body element text inheritance styles.
So, what I recommend when building CSS systems in web page design is the following:
Avoid Bootstrap, or at least turn off its "reboot" system as it is not complete and fails in too many legacy browsers.
Write or install your own HTML reset CSS system that changes all HTML design to a clean universal design all known browsers can share. This way they all start out looking the same, and the body element carries some critical text inheriting features you can revert back to.
When needing to revert back to a CSS default style on any element, simply use all:revert, which will reset styles on any element back to either your "reset" style sheet properties inherited from the body tag or go up the tree and back to the browser's default UA style sheet. Again, this will return your element's style properties back to either the browser's default UA style for the element or to the body tag's styles. If your "reset" sheet has carefully applied inheriting text styles to all browsers on the body element, they will be part of your element's default values you can revert to.
Note: Many web browser's do not support all:revert (Like Internet Explorer). So I recommend you combine all:revert with initial and inherit to force resets on some properties in older browsers.
The solution above will force all CSS in most modern browsers built today back to the original browser's defaults on an element-by-element basis. By using your own reset sheet, all the browsers will have the same default style on the body element which all child elements inherit. It means when you revert back an element, its default will include your browser's default styles but also any text-inheriting styles added to the body tag all child elements inherited.
Unfortunately, there's few good "reset" sheets online that do this well, combining your browser's default UA style sheet with your reset sheet. Very few have been carefully designed to reset CSS on elements for every browser known and all known versions, as well. You could write your own. Here is a very good CSS system you can use that does this for you I recommend: Universal CSS Framework
I think some of these should work:
/* Valeurs avec mot-clé */
clear: none;
clear: left;
clear: right;
clear: both;
clear: inline-start;
clear: inline-end;
/* Valeurs globales */
clear: inherit;
clear: initial;
clear: unset;
sources :
toast rm -rf/*
lmgtfy : "css3+clear" on any search engine
https://developer.mozilla.org/fr/docs/Web/CSS/clear
You can use unset,
say you want to set border color to browser default
.navigation input {
padding: 0;
margin: 0 30em;
border-color: unset;
}
this will unset the style inherited from other classes.
Scenario
Visit this link for Codehttps://plnkr.co/edit/yjGTX0XvOZIqL17Co2MF?p=info
I do not want my innerDiv to get modified by CSS in outerDiv.
Is there some way to achieve this?
(contents(HTML) of InnerDiv are loaded via ajax call , and the resulting page already has its own CSS and both CSS files are messing up all the layouts and formats)
From a previous answer: all: initial isn't supported by Edge (Safari is finally OK)
So you can reset manually a hundred of properties if you really really really want to be sure (forget the most obscure ones you know you don't use. If you're a third party, well no luck).
You can (should) add the !important modifier (that's one of those cases where it isn't possible to do in some other way... Fine for me at least)
You can also add a whole lot of specificity to your selectors by adding an id to your component's parent and prefix each of your selectors with that id: #myComponent.my-component .my-component-descendant { color: #333 !important; }. If your existing CSS already uses id (meh), you can go even further (lower, quality wise) and use the same id multiple times in a single selector. #myComponent#myComponent#myComponent.my-component .my-component-descendant { color: #333 !important; }. What is one the crappiest thing you can imagine in a sane project is also a powerful tool when you need to add "enough" specificity.
Food for thought: the modern way of setting box-sizing by setting it on :root and then letting inheritance do its job can be helpful (or not) https://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/
Advantage: if you set another value on a descendant, descendants of the latter will inherit from it. You now have a whole part of your DOM inheriting from another value.
You can override the properties in you innerdiv; here I have overwritten the background-color property of the outerdiv
#outerMostDiv {background-color:red;}
#innerDiv {background-color:yellow;}
<div id="outerMostDiv">
<!-- SOME CSS HERE (say Outer CSS)-->
outer div
<div id="innerDiv">
<!-- some CSS HERE -->
innerdiv
</div>
</div>
Let say I have this external "style.css" sheet:
p.class1 {
background-color: blue;
}
And my HTML content is this:
<head>
<link rel="stylesheet" type="text/css" href="style.css" />
<style>
p.class1 {
background-color: red;
}
p.class2 {
background-color: green;
}
</style>
</head>
<body>
<p class="class1">This is the first paragraph..</p>
<p class="class2">This is the second paragraph..</p>
</body>
For full source code example, visit this link! When I try this .css() code:
$('p.class1').css("background-color", "green");
It will set the p.class1's background-color inline, like:
<p class="class1" style="background-color: rgb(0, 255, 0);">
When I unset it with .css("background-color", ""), the inline style will be gone and the background will set back to red internally. What I want is to set the internal p.class1 style to "" or to remove it when I unset, so the background will become blue externally.. Is there a right way to manipulate the internal <style>?
Keep note, I don't want to remove the internal <style> element to perform the external p.class1 style if it will also affect the style for p.class2 or any attempt that will affect the style of the other in that element.
It is possible, but you will need to use CSSOM to manipulate the style sheet. This is not a jQuery thing, per se, though jQuery can help in the first stages.
The first step is getting to the internal <style> element in the DOM. The easiest way to do that would be to set an id attribute on it in your HTML and then use document.getElementById() to grab the element on the JavaScript side, but any method that can pick out that individual element will work. Assuming you use an id, the HTML might look like this:
<style id="internalStylesheet">
p.class1 {
background-color: red;
}
p.class2 {
background-color: green;
}
</style>
...and then in the JavaScript side...
var styleElem = document.getElementById('internalStylesheet');
Note that if you use jQuery to do this, you need the actual element, not the jQuery collection returned by jQuery().
Once you have the element, you can get into the CSSOM side through its .styleSheet property. Once you're in the stylesheet, the next step is to find the exact rule you want. CSS rules don't have unique IDs like DOM nodes can, so your only option is to search the list:
var desiredRule = null;
for (var i = 0; i < styleElem.styleSheet.cssRules.length; i += 1) {
if (styleElem.styleSheet.cssRules[i].selectorText === "p.class1") {
desiredRule = styleElem.styleSheet.cssRules[i];
break;
}
}
Keeping a reference to the rule you want is a good idea if you will have to change it many times. That way you won't have to repeat this search process every time you want to change the rule.
Once you have the rule you want, manipulating the rule is a lot like manipulating inline styles. For actually removing properties on the rule, I recommend something like this:
desiredRule.removeProperty("background-color");
Note that because of the inefficiences involved in searching the list, I don't recommend you do this unless the rule will affect many elements on the page, and it might have to be changed often. If that fits your use case, then it can be very fast, especially if you keep cached references to the rules you need to change. But this doesn't actually describe many common use cases, and when it doesn't, it's troublesome enough that it could be called premature optimization.
The only way to have a conflicting external CSS file override the inline <style> element without changing your HTML file at all, based on the code in your question, is by adding the !important hack to your external CSS file:
p.class1 {
background-color: blue !important;
}
But this is a hack, is bad, and should not be done, because you are throwing away the "Cascading" part of CSS when you use !important; instead, you should just remove p.class1 { background-color: red; from your inline <style> element, or replace its value with blue, since you don't want red to be used.
Instead, you should have your external stylesheet load after the <style> element. This can be done by simply flipping their order:
<head>
<style>
p.class1 {
background-color: red;
}
p.class2 {
background-color: green;
}
</style>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
This will override the <style>'s p.class1 value of red with the CSS file's p.class1 value of blue.
Alternatively, if you add a wrapper/container element around your <p> elements, you can set your external CSS file to have a more specific selector, which would override the less specific selector in the <style> element. Something like:
HTML:
<div class="wrapper">
<p class="class1">This is the first paragraph..</p>
<p class="class2">This is the second paragraph..</p>
</div>
CSS:
.wrapper p.class1 {
background-color: blue;
}
Since the selector .wrapper p.class1 is more specific than the inline selector p.class1, it will normally override the inline selector.
Firstly, there is no real difference between the external stylesheet and the internal <style> tag. The one defined later will take effect. I presume you have included your CSS before your <style>, so this part of the CSS will never work:
p.class1 {
background-color: blue;
}
Secondly, all inline styles will overwrite any CSS, so your jQuery .css() calls will always work. Setting it to an empty string will remove that inline style property, so it will naturally fall back to the lower-priority stylesheets - in your case,
<style>
p.class1 {
background-color: red;
}
...
</style>
Thirdly, no there is no way to manipulate the internal <style> dynamically. So if you want your p.class1 to revert to blue after inline styles are removed, you should either:
Declare your <link href="external.css"> after your <style>, which would then cancel out your p.class1 internal style. (This then begs the question of: why would you want to include that property for it to be cancelled out then?)
OR
Just use CSS and avoid internal styles.
I'd like to be able to tell if specific CSS properties (width, height, margin, padding, font-size, …) were set by the page author for a DOM element. My goal is to not change elements that have had their dimensions explicitly set, but to change those that have not.
function isPropertySet(elem, "width") should return true if the page author set the width CSS property either inline (style="width: 100px;"), or via a stylesheet.
This is not straightforward because the layout engine infers these values, and it seems that however I try to access them the browser has supplied values.
For instance, I've tried getComputedStyle(elem).getPropertyValue("width"), but this returns the computed width (not surprising given the name).
The style property, e.g. elem.style.width, isn't sufficient because it doesn't include properties set in stylesheets.
Before I go to the immense pain of searching through the stylesheets, does anyone have a better way?
Thanks!
If you want to supply default style set for the elements which were not customized, than the easiest way would be to create your own stylesheet and put it at the top, before any other CSS files. This way, every element customized elsewhere will overwrite your default styles. Be careful with the cascading order: not only your styles should precede every other, but the selectors should also be general enough.
If, on the other hand, for some reason you want to know through JavaScript whether the element was customized, then it's not possible, unless you want to compare the particular style with the default one, given that default styles may vary from browser to browser. For example, in Firefox, the default style for <h1/> is:
h1 {
display: block;
font-size: 2em;
font-weight: bold;
margin: .67em 0;
}
while Chrome has a slightly different style:
h1 {
display: block;
font-size: 2em;
-webkit-margin-before: 0.67em;
-webkit-margin-after: 0.67em;
-webkit-margin-start: 0px;
-webkit-margin-end: 0px;
font-weight: bold;
}
This creates a problematic edge case. Imagine I want all <h1/> be font-weight:normal; font-size: 200%;, but there is one specific title on one specific page which I want to be exactly 2em and be displayed in bold. You'll think that the title is not customized, and override its style, while in fact, it was customized, the size and weight being set on purpose.
If you aren't worried about inherited styles and only the specific DOM element then maybe you can dynamically create the specific element&classname (so it only has CSS styles) and then examine it's width using the above methods and compare it?
The best way I have found to answer this question from JavaScript is to create a temporary element, that is not attached to the dom, and read my default values from that. I then test the default values against the values read from the element I'm testing (using jQuery or getComputedStyle) - if they compare then it's a best guess they haven't been set. Obviously this has a downside in the fact that if the element has had it's property set to the exact same value as the default you can't tell the difference.
Something like this
function hasDefaultStyle(elm, prop) {
var def = $('<'+$(elm).attr('tagName')+' />').css(prop);
return $(elm).css('prop') == def;
}
When dealing with different dimension metrics i.e. percent, cm, em and so on - these have to be dealt with in a different way—on browsers other than FireFox at least—due to the computed problem you mention.
FireFox does the right thing in my opinion and that when you request styles from an element that hasn't been placed in the dom it returns the original values i.e. like 50%.
For more information on how to solve at least the percent problem you can see my answer here:
Determine whether element has fixed or percentage width using JavaScript
It is rather ridiculous that such methods are necessary however :/
This is for research purposes on http://cssfingerprint.com
Consider the following code:
<style>
div.csshistory a { display: none; color: #00ff00;}
div.csshistory a:visited { display: inline; color: #ff0000;}
</style>
<div id="batch" class="csshistory">
<a id="1" href="http://foo.com">anything you want here</a>
<a id="2" href="http://bar.com">anything you want here</a>
[etc * ~2000]
</div>
My goal is to detect whether foo has been rendered using the :visited styling.
I want to detect whether foo.com is visited without directly looking at $('1').getComputedStyle (or in Internet Explorer, currentStyle), or any other direct method on that element.
The purpose of this is to get around a potential browser restriction that would prevent direct inspection of the style of visited links.
For instance, maybe you can put a sub-element in the <a> tag, or check the styling of the text directly; etc. Any method that does not directly or indierctly rely on $('1').anything is acceptable. Doing something clever with the child or parent is probably necessary.
Note that for the purposes of this point only, the scenario is that the browser will lie to JavaScript about all properties of the <a> element (but not others), and that it will only render color: in :visited. Therefore, methods that rely on e.g. text size or background-image will not meet this requirement.
I want to improve the speed of my current scraping methods.
The majority of time (at least with the jQuery method in Firefox) is spent on document.body.appendChild(batch), so finding a way to improve that call would probably most effective.
See http://cssfingerprint.com/about and http://cssfingerprint.com/results for current speed test results.
The methods I am currently using can be seen at http://github.com/saizai/cssfingerprint/blob/master/public/javascripts/history_scrape.js
To summarize for tl;dr, they are:
set color or display on :visited per above, and check each one directly w/ getComputedStyle
put the ID of the link (plus a space) inside the <a> tag, and using jQuery's :visible selector, extract only the visible text (= the visited link IDs)
FWIW, I'm a white hat, and I'm doing this in consultation with the EFF and some other fairly well known security researchers.
If you contribute a new method or speedup, you'll get thanked at http://cssfingerprint.com/about (if you want to be :-P), and potentially in a future published paper.
ETA: The bounty will be rewarded only for suggestions that
can, on Firefox, avoid the hypothetical restriction described in point 1 above, or
perform at least 10% faster, on any browser for which I have sufficient current data, than my best performing methods listed in the graph at http://cssfingerprint.com/about
In case more than one suggestion fits either criterion, the one that does best wins.
ETA 2: I've added width-based variants of two previous-best test methods (reuse_noinsert, best on Firefox/Mozilla, and mass_insert, its very close competitor). Please visit http://cssfingerprint.com several times from different browsers; I'll automatically get the speed test results, so we'll find out if it's better than the previous methods, and if so by how much. Thanks!
ETA 3: Current tests indicate a speed savings using offsetWidth (rather than getCalculatedStyle/currentStyle) of ~2ms (1.8%) in Chrome and ~24ms (4.3%) in Firefox, which isn't the 10% I wanted for a solid bounty win. Got an idea how to eke out the rest of that 10%?
[new update]
If you wanted the results just for visual presentation then the fastest method would be to use CSS counter..
CSS:
body{
counter-reset: visited_counter;
}
a:visited{
counter-increment: visited_counter;
}
#results:before{
content:counter(visited_counter);
}
This would add the number of visited links before the element with id 'results'.
Unfortunately there is no way to access it from JavaScript, you can only display it..
[initial answer]
You are aware that jQuery supports the :visited selector directly right?
Like $('a:visited')
[update]
As an alternative, you could apply a CSS property that does not rely to the getComputedStyle to retrieve..
Like a:visited{height:1px;display:block;} and then check for offsetHeight.
add a child inside the anchor (for example a span)
use color : inherit
detect the color of the child (JS)
caveat: afaik it won't work on lte ie7
for lte ie7 ull have to
add visibility : hidden on a:visited and visibility : inherit on the child
check the visibility of the child using javascript (hidden = visited)
A similar idea, but sidestepping .getComputedStyle():
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<style type="text/css">
a:visited { display: inline-block; font-family: monospace; }
body { font-family: sans-serif; }
</style>
<script type="text/javascript">
function test() {
var visited = document.getElementById("v").childNodes[1].firstChild.clientWidth;
var unvisited = document.getElementById("u").childNodes[1].firstChild.clientWidth;
var rows = document.getElementsByTagName("tr");
for (var i = 1, length = rows.length; i < length; i++) {
var row = rows[i];
var link = row.childNodes[1].firstChild;
var width = link.clientWidth;
row.firstChild.appendChild(document.createTextNode(link.href));
row.childNodes[2].appendChild(document.createTextNode(width === visited ? "yes" : (width === unvisited ? "no" : "unknown")));
}
}
</script>
</head>
<body onload="test()">
<table>
<tr><th>url</th><th>link</th><th>visited?</th></tr>
<tr id="u"><td></td><td>l</td><td></td>
<tr id="v"><td></td><td>l</td><td></td>
<tr><td></td><td>l</td><td></td>
<tr><td></td><td>l</td><td></td>
</table>
</body>
</html>
The trick, of course, is ensuring that visited and unvisited links have different widths (here, by using sans-serf vs. monospace fonts) and setting them to inline-block so that their widths can be accessed via clientWidth. Tested to work on FF3.6, IE7, Chrome 4, and Opera 10.
In my tests, accessing clientWidth was consistently faster than anything which relied on computed styles (sometimes by as much as ~40%, but widely varying).
(Oh, and apologies for the <body onload="..."> nonsense; it's been too long since I tried to do events in IE without a framework and I got tired of fighting it.)
Since all versions of IE (Yes, even version 8 if you enable quirks) support CSS expressions the color property is still unsafe. You could probably speed up IE testing with this (untested):
a:visited { color: expression( arrVisited.push(this.href) ); }
Also this isn't really covered by your question but you can of course set properties in child nodes very easily to initiate detection and any solution would have to prevent that too:
a.google:visited span { background-image: url(http://example.com/visited/google); }
You need to protect adjacent siblings too, not just descendants:
a.google:visited + span { }
Also untested but you could probably do a heavy speedup using the content property to modify the DOM and then some XPath to find the new nodes.
a.google:visited:before {content: "visited"; visibility: hidden;}
XPath:
visited links = document.evaluate('//a[text()="visited"]')