Combine Calc() with Attr() in CSS

Combine calc() with attr() in CSS

Right now attr() is not supported by default in any major browser for any attributes other then "content". Read more about it here: https://developer.mozilla.org/en-US/docs/Web/CSS/attr

Performing calculations (calc) on data attributes in CSS (e.g. modulus)

Here's a simple JavaScript solution:

var pids = document.querySelectorAll('[data-pid]');

Array.prototype.forEach.call(pids, function(elem, index) {

elem.classList.add('pid-mod-' + (index % 4));

});
.pid-mod-0 {

color: red;

}

.pid-mod-1 {

color: orange;

}

.pid-mod-2 {

color: yellow;

}

.pid-mod-3 {

color: green;

}
<div data-pid="0">0</div>

<div data-pid="1">1</div>

<div data-pid="2">2</div>

<div data-pid="3">3</div>

<div data-pid="4">4</div>

<div data-pid="5">5</div>

<div data-pid="6">6</div>

<div data-pid="7">7</div>

How do I (can I) use attr() to get the z-index, a CSS property, for use with calc() in my style definition?

As far as I'm aware, that isn't possible just with CSS. You can, however, reference the HTML attributes on an element in the CSS property content, and reference HTML attributes in CSS selectors.

So using your code, you could actually create a zIndex (not CSS z-index) attribute attribute on the element (or I created a data-zIndex), then reference that in a content attribute

#test:after {
content: attr(data-zIndex);
background: white;
color: black;
padding: 1em;
display: inline-block;
}

Or you can use a CSS selector to target the element based off of the value of that attribute like...

#test[data-zIndex="0"]:after {
border-radius: 1em;
}

#test[data-zIndex="2"]:after {
background: yellow;
}

Here's a demo with those changes.

function moveZ(amount) {
var box = document.getElementById("test");
var curZ = box.getAttribute('data-zIndex');
if (curZ == "") {
//console.log((typeof curZ) + " curZ=" + curZ);
curZ = 0; //because, for some reason, the initial value of any CSS property when accessed by JavaScript always seems to be null of some sort...
//console.log((typeof curZ) + " curZ=" + curZ);
} else {
//console.log((typeof curZ) + " curZ=" + curZ);
curZ = parseInt(curZ);
//console.log((typeof curZ) + " curZ=" + curZ);
}
var newZ = curZ + amount;
box.setAttribute('data-zIndex',newZ);
}
body {
background-color: #000000;
}

div {
margin: 0px;
padding: 0px;
border-width: 0px;
display: block;
}

#test {
position: absolute;
top: 0px;
left: calc( attr(zIndex) * 10px);
/*This line is the one in question*/
background-color: #ff0000;
z-index: 0;
width: 144px;
height: 288px;
}

#test:after {
content: attr(data-zIndex);
background: white;
color: black;
padding: 1em;
display: inline-block;
}

#test[data-zIndex="0"]:after {
border-radius: 1em;
}

#test[data-zIndex="2"]:after {
background: yellow;
}

#ref {
position: absolute;
top: 0px;
left: 0px;
background-color: #00ff00;
z-index: 1;
width: 288px;
height: 144px;
}
<div id="ref">Reference div</div>
<div id="test" data-zIndex='0' onmouseenter="moveZ(2);" onmouseleave="moveZ(-2);"><br /><br /><br /><br /><br /><br /><br /><br />Test div</div>

calc() function inside another calc() in CSS

It is possible to use calc() inside another calc().

An example:

div{
width: calc(100% - (1% + 30px));/* calc(1% + 30px) is nested inside calc()*/
}
div p{
width: calc(100% - 30px);/*100% is total width of the div*/
}

Update on nested calc with css variables:

.foo {
--widthA: 100px;
--widthB: calc(var(--widthA) / 2);
--widthC: calc(var(--widthB) / 2);
width: var(--widthC);
}

After all variables are expanded, widthC's value will be calc( calc( 100px / 2) / 2), then when it's assigned to .foo's width property, all inner calc()s (no matter how deeply nested) will be flattened to just parentheses, so the width property's value will be eventually calc( ( 100px / 2) / 2), i.e. 25px. In short: a calc() inside of a calc() is identical to just parentheses.

So, the current spec as well proves this using parentheses inside calc() is nested calc.

Learn more about css variables here.

Use css counter in calc

The Question Can I use the counter(skill) inside a calc()

No. You can't.

The calc function does not permit the use of counter functions as its components. From the specs here - https://www.w3.org/TR/css3-values/#calc-notation:

Components of a
calc() expression
can be literal values or
attr() or
calc()
expressions.

There have been many requests for this but always declined. The underlying reason seems to be that the counter() function represents (outputs) a <string> and hence cannot be used directly in calc. Moreover, the counters are considered very expensive for the browsers.

Reference: https://lists.w3.org/Archives/Public/www-style/2016Aug/0082.html

However, there have been proposals for adding a counter-value() function which would return the value as integer and could be used in calc. See here: https://drafts.csswg.org/css-lists-3/#counter-functions (Scroll down to see Issue 4).

So as of now, you cannot use counter inside of calc and the counter-value does not exist yet.

CSS attr() concatenation with url path

It is not possible to create a composite url() value out of two or more strings. On top of the legacy url() value, which isn't even a proper CSS function (see Is there a way to interpolate CSS variables with url()? — which means you can't even do this with custom properties), the proper CSS function version of url() as defined in css-values-3 only accepts a single string.1

You can concatenate multiple strings in a content declaration, but that is a feature of the content property, not of strings in CSS.


1 Since url() accepts a single string, this does mean that a single attr() can be used as a URL value, also new to css-values-3, as attr(image url)... except browser support is nonexistent.

Sass selector combine attribute

SASS is a powerful CSS tool to make use of in programming. It provides a lot of programming logics support like if/else, each, for loop, etc., so in your situation it's better to make use of @each functions in SASS-

$langs: 'en','zh-TW','zh-CN'; // Define the array for your languages

@each $lang in $langs{
body{
&[lang="#{$lang}"]{
font-family: 'Noto Sans TC', sans-serif;
}
}
}

this will result in something like this-

body[lang="en"] {
font-family: 'Noto Sans TC', sans-serif;
}

body[lang="zh-TW"] {
font-family: 'Noto Sans TC', sans-serif;
}

body[lang="zh-CN"] {
font-family: 'Noto Sans TC', sans-serif;
}

You can check this here - http://www.sassmeister.com/,

Also it depends what kind of compiler tool you're using, for ex. if you're using gulp and it's gulp-sass package it'll minimize the code and write it in a comma-seperated way.

For more experiments and advance features refer the below links-

http://thesassway.com/intermediate/if-for-each-while

https://www.sitepoint.com/sass-maps-vs-nested-lists/

https://css-tricks.com/the-sass-ampersand/



Related Topics



Leave a reply



Submit