attr() in CSS and its implementation [duplicate] - css

I have this in my HTML document:
<a class="wbutton tint" data-tint="rgba(255,0,0,.5)" href="#">This should be red, with an opacity of 0.5</a>
and this in the CSS file:
.window > .content .wbutton.tint {
border: solid thin attr(data-tint, color);
box-shadow: inset 0 0 50px attr(data-tint, color);
}
Firefox returns a CSS error in Firebug. Am I doing something wrong?
According to the W3C specs for the attr() function, it should work.
(Also, there's a page about attr() in the MDN Wiki, so I assume it should at least work in Firefox)

Looking at the grammar that's given in the spec:
attr( <attr-name> <type-or-unit>? [ , <fallback> ]? )
It looks like the comma between the attribute name and the unit to be used needs to be dropped:
.window > .content .wbutton.tint {
border: solid thin attr(data-tint color);
box-shadow: inset 0 0 50px attr(data-tint color);
}
However, even if you have the right syntax, it won't work either. It turns out, there are no known implementations of the level 3 version of attr() as of 2012...2020. To make matters worse, it's still at-risk as of the latest editor's draft of the spec.
But not all is lost: if you'd like to see this feature implemented in upcoming browsers, there is still time to suggest it in the relevant feedback channels! Here are the proposals that have been put out so far:
Microsoft Edge Platform, currently Under Consideration (ht Lea Verou!)
For the record, the basic Level 2.1 version is fully supported across recent versions of all major browsers, including IE8+ and Firefox 2+, and is used with the content property for the :before and :after pseudo-elements for generated content. The MDN browser compatibility table is applicable only to this version, and not the CSS3 version.

As of today, the attr() in CSS3 only supports to get values from the HTML5 data attribute to set the content of an element. There is a nice fiddle whichs shows it.
I have tested it in Google Chrome 35, Mozilla Firefox 30 & Internet Explorer 11.
If you want to use HTML5 data attributes for different things in CSS3, like setting the width and the height of elements, then you need an additional JavaScript library.
Fabrice Weinberg wrote a CSS3 attr() Polyfill which handles data-width and data-height. You can find Fabrice's GitHub repository here: cssattr.js.

I found hack. This is not attribute, but manipulate directly on styles. In Chrome Canary, you can use custom css properties, and JS for manipulate properties.
In CSS:
.some { background-position: var(--x) 0; }
In JS:
element.style.setProperty("--x", "100px", "");
//With same success you can set attribute.
Test case: https://jsfiddle.net/y0oer8dk/
Firefox: https://jsfiddle.net/0ysxxmj9/2/

It does work, but not the way you think. It's not a value that's sent via a variable but more as a trigger to then assign a value to. And because of this it's better to make the data attributes something unique but simple.
A small example might help:
<div class="data"><span data-width="80" data-tint="lime"></span></div>
Then in your css you would put:
.data {height: 50px; width: 100%; background-color: #eee;}
.data > span {display: block; height: 100%;}
.data > span[data-width="80"] {width: 80%;}
.data > span[data-tint="lime"] {background-color: rgba(118, 255, 3, 0.6);}
It's pointless if your doing it on a small scale but on a larger scale and with some help from SCSS some things become easier, like..
#for $i from 1 through 100 {
&[data-width="#{$i}"] {
.data > span {
width: calc(#{$i} * 1%);
}
}
}
That will compile into CSS every percentage possibility allowing you to set your span width with data-width.
Check out the fiddle

What you are attempting to accomplish can't currently be achieved with data attributes as has been said by several people already. While the answer from #Eugene will work, it will add an incredible amount of bloat to your css file and is therefore unreasonable. #benny-neugebauer was correct in saying that it isn't possible with data attributes but he isn't entirely correct in saying that you need javascript to accomplish it. There is a way to achieve it with html and css only...
We need to start by converting your attribute from a data attribute to a css variable.
<a class="wbutton tint" data-tint="rgba(255,0,0,.5)" href="#">This should be red, with an opacity of 0.5</a>
becomes
<a class="wbutton tint" href="#" style="--data-tint:rgba(255,0,0,.5);">This should be red, with an opacity of .5</a>
Next, we need to modify your css slightly. It should also be noted that since you used a comma in your attr(), where you have color is where you are supposed to, or can, include a fallback in case your variable is invalid. If you wanted to declare that the attribute value should be a color then you would not use the comma.
.window > .content .wbutton.tint {
border: solid thin attr(data-tint, color);
box-shadow: inset 0 0 50px attr(data-tint, color);
}
becomes
.window > .content .wbutton.tint {
border: solid thin var(--data-tint);
box-shadow: inset 0 0 50px var(--data-tint);
}
You can see it in action below.
.window>.content .wbutton.tint {
border: solid thin var(--data-tint);
box-shadow: inset 0 0 50px var(--data-tint);
}
<div class="window">
<div class="content">
<a class="wbutton tint" href="#" style="--data-tint:rgba(255,0,0,.5);">This should be red, with an opacity of .5</a>
</div>
</div>
Here is an article by Chris Coyier at css-tricks.com that provides more information.

Related

Changing checkbox layout without using label

Is it possible to change the layout of a checkbox without adding the label tag in CSS?
Things like this do not have any effect:
input[type=checkbox][disabled] {
background-color: green;
border: 10px solid red;
}
The only thing I found so far is how to change the opacity.
I'm not sure if this will be much use to you, but it does allow you to "style up" a checkbox without the need for a label. I've remove the disabled flag so you can swap between the different styles. Shouldn't be difficult to add it back in if this will work for you.
Fiddle is here.
input[type=checkbox]:checked:before {
background-color: green;
border: 10px solid red;
}
input[type=checkbox]:before {
content:'';
display:block;
height:100%;
width:100%;
border: 10px solid green;
background-color: red;
}
The above only works on Chrome, however, it seems like Chrome is in the wrong where the specification is concerned.
A fuller answer here: CSS content generation before or after 'input' elements
As of today there is no solution, if we assume a cross browser functional styling, to style the <input type="checkbox" > alone, other than a few properties like opacity, width, height, outline (and maybe a few more).
Using a label (or other content elements) is what you need to do that and here is a good (which this question is likely a duplicate of) post with lots of options: How to style checkbox using CSS?
Note: If you know more properties, feel free to update this answer.

currentColor seems to get "stuck" in Safari

I'm trying to use CSS currentColor as a border-color to generate CSS triangles using :after content. This works great in all browsers I've tried, except one: Safari seems to be caching the currentColor from the first triangle it generates, and then using that everywhere.
Here's what I'm seeing -- expected behavior from Chrome (and Firefox, and IE9+):
Incorrect behavior from Safari 8.0.4 on Yosemite 10.10.2 (same on iOS 8.2) -- notice all three triangles are red, not the currentColor of their elements:
Here's a fiddle with the full code demonstrating the problem.
The relevant CSS:
span {
display: inline-block;
border-bottom: 2px solid currentColor;
}
span::after {
/* Generate a triangle (based on Foundation's css-triangle mixin) */
content:"";
display: inline-block;
width: 0;
height: 0;
border: inset 0.4em;
/* Safari seems to cache this currentColor... */
border-color: currentColor transparent transparent transparent;
border-top-style: solid;
}
.red { color: #c00; }
.blue { color: #009; }
The HTML is simple:
<div>
<span class="red">Red</span>
<span>Default</span>
<span class="blue">Blue</span>
</div>
Is this a bug in Safari? A matter of interpretation on the CSS spec?
More importantly, any suggestions for working around this? I'd hate to have to explicitly declare the color in separate :after rules for each element. (Using currentColor really simplifies maintenance as our other CSS changes.)
So, this turns out to be an actual Safari bug (which might be fixed soon).
I was able to work around it using this suggestion that border-color defaults to currentColor. Replace this:
border-color: currentColor transparent transparent transparent;
with expanded properties that avoid mentioning currentColor:
/* border-top-color: currentColor; is the default behavior */
border-right-color: transparent;
border-bottom-color: transparent;
border-left-color: transparent;
and the problem goes away in Safari (and it still works in the other browsers).
Even I faced a similar issue, so i have to go with a small js trick.
With this trick we can use the currentColor attribute to be set correctly in the desired elements. but it can be achieved only for normal elements. so i moved the pseudo elements into normal elements.
You have to force safari to redraw elements to achieve this. To achieve redrawing elements simply hide and show it.
var nodeStack =[element];
while (node = nodeStack.pop()) {
if (node.nodeType == 1) {
node.style.display="none";
node.style.display="";
var i = node.childNodes.length;
while (i--) {
nodeStack.push(node.childNodes[i]);
}
}
}
Check this simple codepen (Your code with little modification)
and also read this for brief info
Pseudo elements cannot be achieved through this trick. You have to move that into a span or some other element.

User style !important not taking precedence

According to the W3C, user important style declarations are supposed to have the highest priority, higher than author important declarations, but I'm not seeing that happen. If you go to jsfiddle (intentionally blank, I'm referring to the site itself), and look at the styling for the iframe, you'll see the following:
#content textarea, #content iframe
{
background: none repeat scroll 0 0 #FFFFFF;
border: 0 none !important;
box-shadow: 0 1px 3px #E4E4E4 inset;
}
I made a user style (using stylish) with the following css:
#namespace url(http://www.w3.org/1999/xhtml);
#-moz-document domain("jsfiddle.net") {
iframe
{
border: 4px solid red !important;
}
}
When I applied it, nothing happened. If I use firebug to disable the rule or remove the !important specified by jsfiddle, it works. It also works if I change the selector in my user style to #content iframe.
W3C specifically states: 3. Sort rules with the same importance and origin by specificity of selector Since the user style rule should have higher importance, specificity shouldn't have any effect here, so why does the style not apply when using only iframe as the selector?
(tested using firefox 24.2 in case that matters)
Since I haven't gotten an answer, let me give an actual example of what I'm trying to do, and why changing the selector won't help. Here's a dabblet demonstrating the exact html/css/js I'm dealing with.
The following userstyle properly applies a red border, but has no effect on the text color.
#-moz-document domain("preview.dabblet.com"){
#test
{
color: white !important;
border: 1px solid red;
}
}
Using a userstyle, how can I force the text to always be white?
You are correct that an !important declaration of origin "user" should take precedence over any declaration of origin "author", regardless of importance or specificity. However you are making an assumption that Stylish applies its styles with the "user" origin.
Since Stylish 1.4.1 for Firefox, it will apply styles with "author" origin by default. One reason for this change was compatibility with Stylish for other browsers. Their APIs only allow Stylish to add "author" origin styles, which meant that a style that worked in Firefox didn't work in Chrome. Yours is one example of where this would be the case.
The best way to fix this (and to ensure compatibility with other browsers, should you share your style on userstyles.org), is to increase the specificity of your selector to something greater than that of the site's CSS. The simplest way to do so would be to use the same selector as the site, but add a body type selector at the start:
#namespace url(http://www.w3.org/1999/xhtml);
#-moz-document domain("jsfiddle.net") {
body #content iframe {
border: 4px solid red !important;
}
}
There are cases where this isn't feasible: a style that affects iframes on many sites that couldn't be so specific with its selector, or a style trying to override an !important declaration inside an HTML style attribute. Stylish for Firefox allows you to switch your style to the "agent" origin with a special comment: /* AGENT_SHEET */. This will have the effect of your !importants beating anything the site can do (much like the "user" origin), but it will not work in other browsers and can cause bad things like crashes, so this is only suggested if the above method is completely unworkable for you.
All of this is described on Stylish's wiki along with some info less relevant to your situation.
You're right on with the specificity idea. The problem is both your rule and jsfiddle's rule use !important which means both rules have the same priority, but the #content textarea, #content iframe rule is more specific.
To solve, you could write your rule as:
#content iframe {
border: 4px solid red !important;
}
See this for more details: http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/#CSS_parsing
That section will give you what you need, but the whole article is extremely interesting.

Stop CSS 'a' styles being applied to images that are linked

I've been instructed to make links on a website have a different colour underline than the font colour. It all seemed quite easy, using border-bottom as below, except that linked images are now also underlined.
Is there a way, without using JS, to stop happening?
a{
color: #6A737B;
text-decoration: none;
}
a:hover{
border-bottom: 1px solid #C60B46;
text-decoration: none;
}
An example - hovering over the below image now adds the border-bottom CSS style to it, which I don't want -
<a title="Dyne Drewett" href="http://test.dynedrewett.com">
<img class="attachment-full" width="202" height="78" alt="Dyne Drewett Solicitors" src="http://test.example.com/Website-Header.png">
</a>
The only static way to do this would be to use a class on image links like:
<a href='http://whatever.url.here/' class='imglink'>
<img src='img/image.png' alt='Alt text'>
</a>
Then apply a CSS style to this class:
a.imglink:hover {
border-bottom: 0px solid;
}
You'd have to declare this AFTER the other a:hover CSS class.
Technically, you cannot set a style on an element based on what elements it contains. You cannot make the border of an a element depend on the presence of an img element inside (and this is what you are dealing with). Using classes would help, but from the comments, it seems that this is out of the question.
There’s a workaround: place each image at the bottom of the containing element (not on the baseline as per defaults), and shift it down one pixel, or whatever the border width might be. This way, the image will cover the bottom border, provided that the image has no transparency. CSS code:
a img {
vertical-align: bottom;
position: relative;
top: 1px;
}
This slightly changes the position of all images, so it might affect the overall layout unless you take precautions.
I'd suggest adding a class to the link, so you can do
a.imglink:hover{
border:0;
}
Alternatively, if you can't control that class, you can try adding a negative margin to your image to ensure the border doesn't show:
a img{
margin:0 0 -1px 0;
}
That -1px might need adjusting based on your other rules
Here's a fiddle to show the negative margin solution: http://jsfiddle.net/QRXGe/
Your solution will require you adding an additional class name to links that wrap images (or anything where the border should be removed). There's no way to sort of "reverse select" unless you want to employ a JavaScript technique.
A jQuery technique would be something like this:
$('a > img').parent().css('border-bottom', 'none');
That will remove a "border-bottom" style from all anchor tags that have image as a direct descendant. But you'll need it on every page, and every page is getting parsed by this script, so it's a little added overhead on each page.
Otherwise, if you have access to the HTML, creating a CSS class to target these specific links such as:
a.img-link{ border-bottom:none; }
And apply it to any link that's around an image such as:
<img src="#" alt="" />
I hope that helps!
Another way to achieve this is to simply make the images in links relative and then offset the bottom to cover the border. 5px seems to do it http://jsfiddle.net/ECuwD/
a{
color: #6A737B;
text-decoration: none;
}
a:hover{
border-bottom: 1px solid #C60B46;
text-decoration: none;
}
a img {
position:relative;
bottom: -5px;
}
a:hover img {
border-bottom:none;
}
or perhaps...
a:hover img.attachment-full {
border-bottom:none;
}
Apparently, what you want is a different behavior for the same markup (<a>) based on its content.
Sadly, there is no real way to do this with pure CSS, as this language is not programming language and therefore lacks the condition structures, such as if.
That does not mean that there is no solution! Here is a couple of things you can do:
Declare (say) in your HTML that the element (<a>) should be handled differently (with classes, in your case either <a class="text"> or <a class='image'>.
Use JavaScript to change your style dynamically, which means based on conditions, such as content for instance. In your case it would probably be something like:
function onLoad() {
for (var element in document.body) {
// look for links
// if this is a link:
// look for image inside link
// if there is one:
// remove the border
}
}

Load sections of a css file depending on the browser

There are buttons on my website that look overly skinny in Chrome compared to Firefox. The button's HTML looks like: <button name="shutdown" type="submit" value="df" class="boton"> Press </button>
My CSS attempt looks like:
.boton {
font-size: 17px;
color: #000;
background: #ee3333;
background: rgba(225, 50, 50, 0.6) !important;
font-family: lucida console;
border: 1px solid #FF4444;
padding: 2px;
-moz-border-radius: 7px;
border-radius: 7px;
cursor:pointer;
}
.chrome .boton
{
padding: 5px !important;
}
I'm not sure if I'm doing this right. ".boton" does indeed change the style of the button, but the padding doesn't change in Chrome. What's wrong here?
The reason that the padding isn't applying to the element is due to the fact that there is no chrome class assigned to any element. There are various hacks around certain Vendor-Specific styles, see this article, but no browser applies a class of .chrome or .moz or anything like that.
However, to achieve more "horizontal" padding, you can use the -webkit-padding-start(padding-left) and the -webkit-padding-end(padding-right). Currently I do not believe there is full padding, or vertical padding for these yet. Be sure when using these to write the -webkit-padding-start, or whichever rule you use, after your padding rule. Otherwise the latter will overwrite the former and both will be lost.
Unless you've also added some browser sniffing that adds the class .chrome etc. to the body that class has no effect.
On the other hand the box model of Firefox and Chrome is not radically different, but the defaults for padding, border, margins etc. may be different. Just explicitly set those values and they should most likely render the same (give or take a few pixels because of different rounding errors). You should not need to add custom css for each browser (but if you use experimental css features like -moz-border-radius and -webkit-border-radius with vendor prefixes you should use all of them in at the same time; the others will ignore the unknown properties).
The different versions of IE (Internet Explorer) do have a radically different box models, and if you cannot get some version of IE to render something correctly with the standard css you should use conditional comments to include IE specific css overrides after the main css file.

Resources