CSS - modify parent based on first child - css

Is there a way in CSS to modify the parent element, given the first child?
In my case, this would be to format a table cell differently if the first child is a link.
<td>Hello</td>
<td>Go here!</td>
<style>
td { padding: 5px; } /* Normal cell */
?? { padding: 0px; } /* Cell with link as first child */
</style>

No, but you can think of a different approach and do something like:
td { padding: 5px; } /* Normal cell */
td a { margin: -5px; } /* Cell with link as first child */
There are many other ways to do the similar, of course.
CSS4 should offer a :has pseudo class which would do exactly what you wanted, but we need to wait for it.

Related

CSS Selector to override MudBlazor styles, but only in certain containers

How can I override library classes, but only within a specific container that I've styled with my own class?
I think I am just not understanding how to format the right selector. Here's the background: I am not a CSS expert, but we lost ours, and now the Data Base Guy has to push through :) We use the MudBlazor library in server-side Blazor, but I think this is "just a CSS" question.
The library pre-defines certain styles, and we need to override them. For example, the library defines .mud-table-dense .mud-table-row .mud-table-cell, which, if I understand correctly, means applied to mud-table-cell when inside mud-table-row inside mud-table-dense. (I could look up the styles in their source, but as far as the project is concerned, these "base styles" are buried deep in the library, somewhere.)
The earlier code in our project just over-rode the styles in our own project.css like this:
.mud-table-dense .mud-table-row .mud-table-cell {
padding: 2px 0 0 2px;
padding-inline-end: 24px;
padding-inline-start: 24px;
}
Trouble is that doing so breaks some other scenarios where we want to use their default formats. Keep in mind that I can't change the styles attached to the <td> or <th> directly (at least in most cases), but I can wrap the whole generated output in a div or style one of the higher-level containers in the library with a class.
So, if I wrap the generated table in a "mycontainer" class, I thought I should be able to change the selector to:
.mycontainer .mud-table-dense .mud-table-row .mud-table-cell {
but, then the they don't seem to apply at all.
The .razor html looks like:
<div class="mycontainer">
<MudDataGrid>
<!--- Table details -->
</MudDataGrid>
</div>
So my question boils down to: Given generated content from a library that creates low level elements like that are styled with classes, how can I override those classes, but only within a specific container that I've styled with my own class?
I don't usually answer my own question, but in case this ever comes up in a search.
The question: Given generated content from a library that creates low level elements like that are styled with classes, how can I override those classes, but only within a specific container that I've styled with my own class?
The (very specific) answer for styling a table generated by MudBlazor's MudTable component:
tbody.mud-table-body tr.mud-table-row > td.elk-table-90-l,
thead.mud-table-head tr.mud-table-row > th.elk-table-90-l,
col.elk-table-90-l {
width: 90px;
overflow: hidden;
text-overflow: clip;
padding: 0;
padding-inline-end: 6px;
padding-inline-start: 0px;
text-align: left;
}
tbody.mud-table-body tr.mud-table-row > td.elk-table-dec-r,
thead.mud-table-head tr.mud-table-row > th.elk-table-dec-r,
col.elk-table-dec-r {
width: 120px;
overflow: hidden;
text-overflow: clip;
padding: 0 35px 0 0 !important;
/* padding-inline-end: 30px;
padding-inline-start: 0px;*/
text-align: right;
}
thead.mud-table-head tr.mud-table-row > th.elk-table-dec-r.sort {
/* Take back out some padding in the header to allow for the hidden sort-icon*/
padding: 0 12px 0 0 !important;
}
.elks-table div.mud-table-container table tbody tr,
.elks-table div.mud-table-container table tbody tr *
.elks-table div.mud-table-container table tbody tr td,
.elks-table div.mud-table-container table tbody tr th * {
overflow-y: hidden;
vertical-align: middle;
height: 30px;
padding: 0;
}
.elks-table tbody tr.mud-table-row td.mud-table-cell ,
.elks-table thead tr.mud-table-row th.mud-table-cell {
padding: 0 12px 0 0 ;
}
.elks-table table,
.elks-table .mud-table-root {
table-layout: fixed;
}
I applied:
elks-table to <MudTable> to used fixed table layout and to lock the row height
elks-table-90-l to <col> in <ColGroup> to set the column width
elks-table-90-l to <MudTh> and <MudTd> to set alignment and such
I could break the settings for the TH and the TD into separate rules, but I preferred keeping them together and using one style for all three places in the markup (col, mudth, mudtd).
It might be possible to further simplify, but I stopped after I got all that I needed working.

CSS selector :not(...) [parent has some class]

I want to select all tags with class p, that is child of .row
.row .p {
...
}
but exclude all, that have .disable as parent class (not directly).
I can select both of them like that:
.row .p {
border: 3px solid blue;
}
.disable .row .p {
border: 3px solid red;;
}
But we want to use just one selector
NOTE: between .disable and .row can be any elements.
CLEARIFICATION: .disable .row .p should have no color at all. So if .disable is present somehow in the parent line do NOT make a blue border. just leave it away.
example:
https://codepen.io/miladfm/pen/ELbwMx
Using CSS Custom Properties (aka CSS Variables) you can style an element according to some ancestor if you set a value to this ancestor and get its value on the former. It's inherited throughout the mighty cascadeĀ® and if not set, you can have a default value given by the fallback of var(--custom-prop, fallback)
Support is Edge 15+ or 16+ and other modern browsers for a longer time AFAIK
/* If any ascendant has a given class, no border */
.disable {
--parent-disable-border: none;
}
/* Default border with fallback value of a CSS Variable / Custom Property */
.p {
border: var(--parent-disable-border, 3px solid blue);
}
Codepen (sorry no snippet it currently fails in Firefox)

How can I use the less pre-processor to handle different styles with two divs one after the other?

I have the following HTML:
<div class="float-left inline orderby">
<div class="arrow up" style="margin-bottom: 2px; margin-left: 2px"></div>
<div class="arrow down" style="margin-left: 2px;"></div>
<input type="checkbox" data-ng-model="inverse" style="margin-left: 0px; margin-right: 10px;">
</div>
I'm trying to use the less pre-processor to create my CSS.
How can I use less to create CSS to remove the styles from this example. In particular I am not sure how to handle the difference between the 1st and 2nd DIV
You mean you want to remove the inline styles?
.orderby .arrow, .orderby input {
margin: 0;
&.up {
/* styles for first div */
}
&.down {
/* styles for second div */
}
}
It's a little unclear exactly what your question is. I can read it two ways:
(1) You cannot remove css set with style with LESS
If you actually have a style property on your html elements, then that cannot be directly affected by LESS at all (so it cannot be "removed" by LESS). Additionally, the only way to overcome those styles with LESS is by using the exact same solution you would have available with CSS, the !important attribute (which I despise, but the facts are the facts when it comes to what is available for CSS styling). So this would remove the margins imposed by the style for all direct children in your div (as your example has):
.orderby > * {
margin: 0 !important;
}
But perhaps you want to know how...
(2) You can move the code from the style to the LESS
In which case, it is something like this:
LESS
.orderby {
.arrow {
margin-left: 2px;
&:first-child { /* or could use &.up */
margin-top: 2px;
}
}
input {
margin-left: 0;
margin-right: 10px;
}
}
CSS Output
.orderby {
.arrow {
margin-left: 2px
&:first-child { /* or could use &.up */
margin-top: 2px;
}
}
input {
margin-left: 0;
margin-right: 10px;
}
}

Apply CSS class to multiple objects

I'm trying to apply a css class to all <th class='euroth'></th> which are located in either table.tablesorter-All-Activity or table.tablesorter-Events.
This is what I did
table.tablesorter-All-Activity,.tablesorter-Events th.euroth {
width: 7px;
vertical-align:middle;
text-align: left;
z-index: 5;
}
As a result, the first table is shifted all the way to the left and the second one accepts the style nicely.
Why is that?
Thanks
You have to append th.euroth to your first selector:
.tablesorter-All-Activity th.euroth,
.tablesorter-Events th.euroth {
/* properties go here... */
}

Can you use if/else conditions in CSS?

I would like to use conditions in my CSS.
The idea is that I have a variable that I replace when the site is run to generate the right style-sheet.
I want it so that according to this variable the style-sheet changes!
It looks like:
[if {var} eq 2 ]
background-position : 150px 8px;
[else]
background-position : 4px 8px;
Can this be done? How do you do this?
Not in the traditional sense, but you can use classes for this, if you have access to the HTML. Consider this:
<p class="normal">Text</p>
<p class="active">Text</p>
and in your CSS file:
p.normal {
background-position : 150px 8px;
}
p.active {
background-position : 4px 8px;
}
That's the CSS way to do it.
Then there are CSS preprocessors like Sass. You can use conditionals there, which'd look like this:
$type: monster;
p {
#if $type == ocean {
color: blue;
} #else if $type == matador {
color: red;
} #else if $type == monster {
color: green;
} #else {
color: black;
}
}
Disadvantages are, that you're bound to pre-process your stylesheets, and that the condition is evaluated at compile time, not run time.
A newer feature of CSS proper are custom properties (a.k.a. CSS variables). They are evaluated at run time (in browsers supporting them).
With them you could do something along the line:
:root {
--main-bg-color: brown;
}
.one {
background-color: var(--main-bg-color);
}
.two {
background-color: black;
}
Finally, you can preprocess your stylesheet with your favourite server-side language. If you're using PHP, serve a style.css.php file, that looks something like this:
p {
background-position: <?php echo (#$_GET['foo'] == 'bar')? "150" : "4"; ?>px 8px;
}
In this case, you will however have a performance impact, since caching such a stylesheet will be difficult.
I am surprised that nobody has mentioned CSS pseudo-classes, which are also a sort-of conditionals in CSS. You can do some pretty advanced things with this, without a single line of JavaScript.
Some pseudo-classes:
:active - Is the element being clicked?
:checked - Is the radio/checkbox/option checked? (This allows for conditional styling through the use of a checkbox!)
:empty - Is the element empty?
:fullscreen - Is the document in full-screen mode?
:focus - Does the element have keyboard focus?
:focus-within - Does the element, or any of its children, have keyboard focus?
:has([selector]) - Does the element contain a child that matches [selector]? (Sadly, not supported by any of the major browsers.)
:hover - Does the mouse hover over this element?
:in-range/:out-of-range - Is the input value between/outside min and max limits?
:invalid/:valid - Does the form element have invalid/valid contents?
:link - Is this an unvisited link?
:not() - Invert the selector.
:target - Is this element the target of the URL fragment?
:visited - Has the user visited this link before?
Example:
div { color: white; background: red }
input:checked + div { background: green }
<input type=checkbox>Click me!
<div>Red or green?</div>
Update:
I've written a article regarding the below unique method in CSS-Tricks which goes into futher detail
I've devised the below demo using a mix of tricks which allows simulating if/else scenarios for some properties. Any property which is numerical in its essence is easy target for this method, but properties with text values are.
This code has 3 if/else scenarios, for opacity, background color & width. All 3 are governed by two Boolean variables bool and its opposite notBool.
Those two Booleans are the key to this method, and to achieve a Boolean out of a none-boolean dynamic value, requires some math which luckily CSS allows using min & max functions.
Obviously those functions (min/max) are supported in recent browsers' versions which also supports CSS custom properties (variables).
var elm = document.querySelector('div')
setInterval(()=>{
elm.style.setProperty('--width', Math.round(Math.random()*80 + 20))
}, 1000)
:root{
--color1: lightgreen;
--color2: salmon;
--width: 70; /* starting value, randomly changed by javascript every 1 second */
}
div{
--widthThreshold: 50;
--is-width-above-limit: Min(1, Max(var(--width) - var(--widthThreshold), 0));
--is-width-below-limit: calc(1 - var(--is-width-above-limit));
--opacity-wide: .4; /* if width is ABOVE 50 */
--radius-narrow: 10px; /* if width is BELOW 50 */
--radius-wide: 60px; /* if width is ABOVE 50 */
--height-narrow: 80px; /* if width is ABOVE 50 */
--height-wide: 160px; /* if width is ABOVE 50 */
--radiusToggle: Max(var(--radius-narrow), var(--radius-wide) * var(--is-width-above-limit));
--opacityToggle: calc(calc(1 + var(--opacity-wide)) - var(--is-width-above-limit));
--colorsToggle: var(--color1) calc(100% * var(--is-width-above-limit)),
var(--color2) calc(100% * var(--is-width-above-limit)),
var(--color2) calc(100% * (1 - var(--is-width-above-limit)));
--height: Max(var(--height-wide) * var(--is-width-above-limit), var(--height-narrow));
height: var(--height);
text-align: center;
line-height: var(--height);
width: calc(var(--width) * 1%);
opacity: var(--opacityToggle);
border-radius: var(--radiusToggle);
background: linear-gradient(var(--colorsToggle));
transition: .3s;
}
/* prints some variables */
div::before{
counter-reset: aa var(--width);
content: counter(aa)"%";
}
div::after{
counter-reset: bb var(--is-width-above-limit);
content: " is over 50% ? "counter(bb);
}
<div></div>
Another simple way using clamp:
label{ --width: 150 }
input:checked + div{ --width: 400 }
div{
--isWide: Clamp(0, (var(--width) - 150) * 99999, 1);
width: calc(var(--width) * 1px);
height: 150px;
border-radius: calc(var(--isWide) * 20px); /* if wide - add radius */
background: lightgreen;
}
<label>
<input type='checkbox' hidden>
<div>Click to toggle width</div>
</label>
Best so far:
I have come up with a totally unique method, which is even simpler!
This method is so cool because it is so easy to implement and also to understand. it is based on animation step() function.
Since bool can be easily calculated as either 0 or 1, this value can be used in the step! if only a single step is defined, then the if/else problem is solved.
Using the keyword forwards persist the changes.
var elm = document.querySelector('div')
setInterval(()=>{
elm.style.setProperty('--width', Math.round(Math.random()*80 + 20))
}, 1000)
:root{
--color1: salmon;
--color2: lightgreen;
}
#keyframes if-over-threshold--container{
to{
--height: 160px;
--radius: 30px;
--color: var(--color2);
opacity: .4; /* consider this as additional, never-before, style */
}
}
#keyframes if-over-threshold--after{
to{
content: "true";
color: green;
}
}
div{
--width: 70; /* must be unitless */
--height: 80px;
--radius: 10px;
--color: var(--color1);
--widthThreshold: 50;
--is-width-over-threshold: Min(1, Max(var(--width) - var(--widthThreshold), 0));
text-align: center;
white-space: nowrap;
transition: .3s;
/* if element is narrower than --widthThreshold */
width: calc(var(--width) * 1%);
height: var(--height);
line-height: var(--height);
border-radius: var(--radius);
background: var(--color);
/* else */
animation: if-over-threshold--container forwards steps(var(--is-width-over-threshold));
}
/* prints some variables */
div::before{
counter-reset: aa var(--width);
content: counter(aa)"% is over 50% width ? ";
}
div::after{
content: 'false';
font-weight: bold;
color: darkred;
/* if element is wider than --widthThreshold */
animation: if-over-threshold--after forwards steps(var(--is-width-over-threshold)) ;
}
<div></div>
I've found a Chrome bug which I have reported that can affect this method in some situations where specific type of calculations is necessary, but there's a way around it.
You can use calc() in combination with var() to sort of mimic conditionals:
:root {
--var-eq-two: 0;
}
.var-eq-two {
--var-eq-two: 1;
}
.block {
background-position: calc(
150px * var(--var-eq-two) +
4px * (1 - var(--var-eq-two))
) 8px;
}
concept
Below is my old answer which is still valid but I have a more opinionated approach today:
One of the reasons why CSS sucks so much is exactly that it doesn't have conditional syntax. CSS is per se completely unusable in the modern web stack. Use SASS for just a little while and you'll know why I say that. SASS has conditional syntax... and a LOT of other advantages over primitive CSS too.
Old answer (still valid):
It cannot be done in CSS in general!
You have the browser conditionals like:
/*[if IE]*/
body {height:100%;}
/*[endif]*/
But nobody keeps you from using Javascript to alter the DOM or assigning classes dynamically or even concatenating styles in your respective programming language.
I sometimes send css classes as strings to the view and echo them into the code like that (php):
<div id="myid" class="<?php echo $this->cssClass; ?>">content</div>
You could create two separate stylesheets and include one of them based on the comparison result
In one of the you can put
background-position : 150px 8px;
In the other one
background-position : 4px 8px;
I think that the only check you can perform in CSS is browser recognition:
Conditional-CSS
CSS is a nicely designed paradigm, and many of it's features are not much used.
If by a condition and variable you mean a mechanism to distribute a change of some value to the whole document, or under a scope of some element, then this is how to do it:
var myVar = 4;
document.body.className = (myVar == 5 ? "active" : "normal");
body.active .menuItem {
background-position : 150px 8px;
background-color: black;
}
body.normal .menuItem {
background-position : 4px 8px;
background-color: green;
}
<body>
<div class="menuItem"></div>
</body>
This way, you distribute the impact of the variable throughout the CSS styles.
This is similar to what #amichai and #SeReGa propose, but more versatile.
Another such trick is to distribute the ID of some active item throughout the document, e.g. again when highlighting a menu: (Freemarker syntax used)
var chosenCategory = 15;
document.body.className = "category" + chosenCategory;
<#list categories as cat >
body.category${cat.id} .menuItem { font-weight: bold; }
</#list>
<body>
<div class="menuItem"></div>
</body>
Sure,this is only practical with a limited set of items, like categories or states, and not unlimited sets like e-shop goods, otherwise the generated CSS would be too big. But it is especially convenient when generating static offline documents.
One more trick to do "conditions" with CSS in combination with the generating platform is this:
.myList {
/* Default list formatting */
}
.myList.count0 {
/* Hide the list when there is no item. */
display: none;
}
.myList.count1 {
/* Special treatment if there is just 1 item */
color: gray;
}
<ul class="myList count${items.size()}">
<!-- Iterate list's items here -->
<li>Something...</div>
</ul>
You can use not instead of if like
.Container *:not(a)
{
color: #fff;
}
Set the server up to parse css files as PHP and then define the variable variable with a simple PHP statement.
Of course this assumes you are using PHP...
This is a little extra info to the Boldewyn answer above.
Add some php code to do the if/else
if($x==1){
print "<p class=\"normal\">Text</p>\n";
} else {
print "<p class=\"active\">Text</p>\n";
}
CSS has a feature: Conditional Rules. This feature of CSS is applied based on a specific condition. Conditional Rules are:
#supports
#media
#document
Syntax:
#supports ("condition") {
/* your css style */
}
Example code snippet:
<!DOCTYPE html>
<html>
<head>
<title>Supports Rule</title>
<style>
#supports (display: block) {
section h1 {
background-color: pink;
color: white;
}
section h2 {
background-color: pink;
color: black;
}
}
</style>
</head>
<body>
<section>
<h1>Stackoverflow</h1>
<h2>Stackoverflow</h2>
</section>
</body>
</html>
As far as i know, there is no if/then/else in css. Alternatively, you can use javascript function to alter the background-position property of an element.
Yet another option (based on whether you want that if statement to be dynamically evaluated or not) is to use the C preprocessor, as described here.
You can use javascript for this purpose, this way:
first you set the CSS for the 'normal' class and for the 'active' class
then you give to your element the id 'MyElement'
and now you make your condition in JavaScript, something like the example below... (you can run it, change the value of myVar to 5 and you will see how it works)
var myVar = 4;
if(myVar == 5){
document.getElementById("MyElement").className = "active";
}
else{
document.getElementById("MyElement").className = "normal";
}
.active{
background-position : 150px 8px;
background-color: black;
}
.normal{
background-position : 4px 8px;
background-color: green;
}
div{
width: 100px;
height: 100px;
}
<div id="MyElement">
</div>
You can add container div for all your condition scope.
Add the condition value as a class to the container div. (you can set it by server side programming - php/asp...)
<!--container div-->
<div class="true-value">
<!-- your content -->
<p>my content</p>
<p>my content</p>
<p>my content</p>
</div>
Now you can use the container class as a global variable for all elements in the div using a nested selector, without adding the class to each element.
.true-value p{
background-color:green;
}
.false-value p{
background-color:red;
}
Besides the answers above, soon another way to directly use if/else -like conditions, and even more closely aligned with other scripting languages, would be via #when / #else conditionals. These conditionals would be implemented to exercise easily recognizable logic chain, for example:
#when supports(display: flex) {
.container {
display: flex
}
} #else media and (min-width: 768px) {
.container {
min-width: 768px
}
} #else {
.container {
width: 100%
}
}
As of February 2022 there is no browser support. Please see this W3C module for more info.
(Yes, old thread. But it turned up on top of a Google-search so others might be interested as well)
I guess the if/else-logic could be done with javascript, which in turn can dynamically load/unload stylesheets. I haven't tested this across browsers etc. but it should work. This will get you started:
http://www.javascriptkit.com/javatutors/loadjavascriptcss.shtml
If you're open to using jquery, you can set conditional statements using javascript within the html:
$('.class').css("color",((Variable > 0) ? "#009933":"#000"));
This will change the text color of .class to green if the value of Variable is greater than 0.

Resources