Use unknown values as selectors in Less - css

Given this markup:
<div class="parent" data-active="typeA">
<div class="child" data-show="typeA">Show only when parent=typeA</div>
<div class="child" data-show="typeB">Show only when parent=typeB</div>
<div class="child" data-show="typeC">Show only when parent=typeC</div>
</div>
I'm trying to write a globally applicable LESS rule that only displays a child when its data-show attribute matches the parent's data-active attribute.
Something like this:
.parent {
.child { display:none; }
&[data-active="?"] .child[data-show="?"] { display:block; }
}
...where ? should not be a fixed value, but a condition that applies no matter the value, as long as they are the same.
Any ideas?

As LESS gets compiled to CSS and there is no generic approach for doing this in CSS, I only come up with a solution that requires you to know every possible type.
.parent {
.child { display: none; }
&[data-active="typeA"] {
.child[data-show="typeA"] { display: block; }
}
&[data-active="typeB"] {
.child[data-show="typeB"] { display: block; }
}
&[data-active="typeC"] {
.child[data-show="typeC"] { display: block; }
}
}
Depending on your preferences and to avoid redundancy you could also define a function for adding the different types.
.parent {
.child { display: none; }
.addType("typeA");
.addType("typeB");
.addType("typeC");
}
.addType(#type) {
&[data-active="#{type}"] {
.child[data-show="#{type}"] { display: block; }
}
}
And if you want to make this even more generic, you could define an array of types and call .addType for each of the types like this:
#types: "typeA", "typeB", "typeC";
.parent {
.child { display: none; }
.-(#i: length(#types)) when (#i > 0) {
#type: extract(#types, #i);
.addType(#type);
.-((#i - 1));
} .-;
}
.addType(#type) { /* see above */ }

Related

scss prepending parent selector

I have a project where legacy code has classes like
promo game-promo
I've got the chance to clean up the css by changing to scss but the issue I'm trying to cover is I'd like to nest promo and have game- prepend the parent.
.promo {
display: flex;
game-& {
color: black;
}
}
I'd have liked the above to work but it doesn't and wondering if anyone has come across any ways of achieving what I'm after?
.game-promo {
color: black;
#at-root .promo {
display: flex;
}
}
It seems its not possible so after re-jigging the code I have now got this.
You can't do what you're trying. The "&" is used to get the current selector, in your case : game-.promo or .game-.promo if you add the class selector but it can't work.
In your case, you can do :
.game-promo {
color: black;
.promo {
display: flex;
}
}
Or rename your classes name : (I give an example with inverting the logic of your names)
Parent with ".promo"
Child with ".promo-game"
So you could do :
.promo {
//properties
&-game {
//properties
}
}
It is possible but not very pretty (code on jsFiddle):
/** see https://gist.github.com/Bamieh/912a6f0b63cbb53f3ad0bd8df7171c6a */
#function parse-dotless($class) {
$this: quote($class);
#return if(str-slice($this, 0, 1) == ".", str-slice($this, 2, str-length($this)), $this);
}
.promo {
color:yellow;
#at-root .game-#{parse-dotless(&)} {
color: blue;
}
}
<span class="promo">Hello</span>
<span class="game-promo">World</span>
You cannot do exactly what your snippet states using only the & feature. Instead you could build modifier classes like this:
.btn {
&-primary {}
&-secondary {}
}
Which is translated to:
.btn-primary {}
.btn-secondary {}
In your code example, you can invert the rule names:
.promo {
display: flex;
&-game {
color: black;
}
}
Read more about the sass-ampersand

parent selector in less

Normally in less to reference a parent selector is:
.parent {
.grand-pa & {
/* this rules will apply to: .grand-pa .parent {....}
background: grey;
}
}
What I'm trying to do is something similar. example code HTML:
<div class="panel panel-parent">
<div class="panel-child">
{{content}}
</div>
</div>
Less code:
.panel {
.panel-child {
// some rules
&.panel-parent & { //<=== IS IT POSSIBILE SOMETHING LIKE THIS??
// .panel.panel-parent .panel-child{...}
}
}
}
The only solution I have found is to repeat .panel-child:
.panel {
&.panel-parent .panel-child { //<=== Workaround
// .panel.panel-parent .panel-child{...}
}
.panel-child {
// some rules
}
}
}
The order of classes of the same element does not actually matter, i.e. .panel.panel-parent is equal to .panel-parent.panel (both will match <div class="panel panel-parent">), thus you can get what you need with just:
.panel {
.panel-child {
a: a;
.panel-parent& {
b: b;
}
}
}
instead.

CSS select :nth-of-class() alternative

With CSS: how do I target the first class of "approach", the second and the third one. All individually because they need different styles. I can't add an extra class to avoid responsive disorientation.
HTML code:
<div class="approaches">
<div class="col-md-4">
content here...
</div>
<div class="col-md-4">
content here...
</div>
<div class="col-md-4">
content here...
</div>
</div>
CSS code (which doesn't work at the moment):
.approaches .approach:nth-of-type(1){
color: red;
}
.approaches .approach:nth-of-type(2){
color: green;
}
.approaches .approach:nth-of-type(3){
color: blue;
}
There's a <div> between the .approaches and the .approach elements preventing your :nth selector from working properly. The selector looks for elements in their own nesting level, and because the .approach elements are wrapped in <div>s, they have separate nesting levels. Use the selector on the <div>s instead:
.approaches div:nth-of-type(1) .approach {
color: red;
}
.approaches div:nth-of-type(2) .approach {
color: green;
}
.approaches div:nth-of-type(3) .approach {
color: blue;
}
You could use .approaches div:nth-of-type(1) .approach { }, as others have suggested, but this assumes that each and every div inside .approaches has an a with the the .approach class, so it cannot really be considered to be a general way to achieve the equivalent of the non-existent nth-of-class if that's what you want.
To do that, you could use a bit of JS:
[].forEach.call(document.getElementsByClassName('approach'), function(elt, i) {
elt.classList.add('approach-' + i);
});
.approach-1 { color: red; }
Generalizing this for any class:
function add_nth_of_class(cls) {
[].forEach.call(document.getElementsByClassName(cls), function(elt, i) {
elt.classList.add(cls + '-' + i);
});
add_nth_of_class('approach');
However, this will number the classes sequentially throughout the document. To get a true nth-of-class, based on the position within the parent element, we would need to do something like the following, using the little-known TreeWalker API:
function add_nth_of_class(cls) {
var walker = document.createTreeWalker(document, NodeFlter.SHOW_ELEMENT), n;
while (n = walker.nextNode()) { //for each node in turn,
[].filter.call(n.childNodes, function(elt) { //find the children which
return elt.classList.contains(cls); //contain the class we want
}).forEach(function(elt, i) { //and for each of those
elt.classList.add(cls + '-' + (i+1)); //add a numbered class
});
}
}
CSS:
.approach-1 { // targets all elements with class .approach first within their parent
.approaches > div:nth-child(1) .approach {
}
.approaches > div:nth-child(2) .approach {
}
.approaches > div:nth-child(3) .approach {
}

Declare variable conditionally in LESS css

I currently have two Views that are using the same layout. However, they differ from each other in the following aspect:
View Foo:
<div class="MajorSection" id="foo">
</div>
View Bar:
<div class="MajorSection" id="bar">
</div>
And I want to declare #labelWidth differently between these two classes in one .less file so that I don't need to repeat myself with the following code.
.MajorSection {
#labelWidth: 10em;
.editor-label {
width: #labelWidth;
}
input, textarea {
width: (#editorWidth)-(.5em); //border & padding
}
}
In View Foo I want #labelWidth to be 10em, and in Bar I want it to be 20em. Is there anyway to do that?
I think the simplest method to achieve this is to define "depended" styles via parametric mixin, e.g.:
.MajorSection {
#foo& {
.labelStyles(10em);
}
#bar& {
.labelStyles(20em);
}
.labelStyles(#width) {
.editor-label {
width: #width;
}
}
input, textarea {
width: (#editorWidth - .5em); // border & padding
}
}
CSS output:
#foo.MajorSection .editor-label {
width: 10em;
}
#bar.MajorSection .editor-label {
width: 20em;
}
.MajorSection input,
.MajorSection textarea {
width: ...;
}

We're using some code from twitter bootstrap and our divs are off in Internet Explorer (7-9)

The code we used is from the less file that's related to positioning. The website looks great in safari, firefox, and chrome and looks off in IE version 7, 8, and 9. Does bootstrap have a known issue with IE? Probably not since it's so widely used. But I can't really identify what's wrong. Btw, here are two sample pages with the visual bug in Internet Explorer: http://www.presspass.me and a simpler page: http://www.presspass.me/about or you can take a look at the screenshots.
My guess is that it's something small, any help would be appreciated!
/*
* Scaffolding
* Basic and global styles for generating a grid system, structural layout, and page templates
* ------------------------------------------------------------------------------------------- */
// Variables
// Can also be 24 / 20 / 20
// Or 16 / 40 /20
#gridColumns: 24;
#gridColumnWidth: 20px;
#gridGutterWidth: 20px;
#extraSpace: (#gridGutterWidth * 2); // For our grid calculations
#siteWidth: (#gridColumns * #gridColumnWidth) + (#gridGutterWidth * (#gridColumns - 1));
// Mixins
// Clearfix for clearing floats like a boss h5bp.com/q
.clearfix() {
zoom: 1;
&:before,
&:after {
display: table;
content: "";
zoom: 1;
}
&:after {
clear: both;
}
}
// Center-align a block level element
.center-block() {
display: block;
margin-left: auto;
margin-right: auto;
}
.fixed-container() {
width: #siteWidth;
margin-left: auto;
margin-right: auto;
.clearfix();
}
.columns(#columnSpan: 1) {
width: (#gridColumnWidth * #columnSpan) + (#gridGutterWidth * (#columnSpan - 1));
}
.offset(#columnOffset: 1) {
margin-left: (#gridColumnWidth * #columnOffset) + (#gridGutterWidth * (#columnOffset - 1)) + #extraSpace;
}
// Necessary grid styles for every column to make them appear next to each other horizontally
.gridColumn() {
display: inline;
float: left;
margin-left: #gridGutterWidth;
}
// makeColumn can be used to mark any element (e.g., .content-primary) as a column without changing markup to .span something
.makeColumn(#columnSpan: 1) {
.gridColumn();
.columns(#columnSpan);
}
// STRUCTURAL LAYOUT
// -----------------
/*
body {
margin: 0;
}
*/
// Container (centered, fixed-width layouts)
.container {
.fixed-container();
}
// Fluid layouts (left aligned, with sidebar, min- & max-width content)
.container-fluid {
position: relative;
min-width: 940px;
padding-left: 20px;
padding-right: 20px;
.clearfix();
> .sidebar {
position: absolute;
top: 0;
left: 20px;
width: 220px;
}
// TODO in v2: rename this and .popover .content to be more specific
> .content {
margin-left: 240px;
}
}
// BASE STYLES
// -----------
// Quick floats
.pull-right {
float: right;
}
.pull-left {
float: left;
}
// Toggling content
.hide {
display: none;
}
.show {
display: block;
}
// GRID SYSTEM
// -----------
// To customize the grid system, bring up the variables.less file and change the column count, size, and gutter there
.row {
.clearfix();
margin-left: -#gridGutterWidth;
}
// Find all .span# classes within .row and give them the necessary properties for grid columns (supported by all browsers back to IE7)
// Credit to #dhg for the idea
.row > [class*="span"] {
.gridColumn();
}
// Default columns
.span1 { .columns(1); }
.span2 { .columns(2); }
.span3 { .columns(3); }
.span4 { .columns(4); }
.span5 { .columns(5); }
.span6 { .columns(6); }
.span7 { .columns(7); }
.span8 { .columns(8); }
.span9 { .columns(9); }
.span10 { .columns(10); }
.span11 { .columns(11); }
.span12 { .columns(12); }
.span13 { .columns(13); }
.span14 { .columns(14); }
.span15 { .columns(15); }
.span16 { .columns(16); }
// For optional 24-column grid
.span17 { .columns(17); }
.span18 { .columns(18); }
.span19 { .columns(19); }
.span20 { .columns(20); }
.span21 { .columns(21); }
.span22 { .columns(22); }
.span23 { .columns(23); }
.span24 { .columns(24); }
// Offset column options
.row {
> .offset1 { .offset(1); }
> .offset2 { .offset(2); }
> .offset3 { .offset(3); }
> .offset4 { .offset(4); }
> .offset5 { .offset(5); }
> .offset6 { .offset(6); }
> .offset7 { .offset(7); }
> .offset8 { .offset(8); }
> .offset9 { .offset(9); }
> .offset10 { .offset(10); }
> .offset11 { .offset(11); }
> .offset12 { .offset(12); }
}
// Unique column sizes for 16-column grid
.span-one-third { width: 300px; }
.span-two-thirds { width: 620px; }
.row {
> .offset-one-third { margin-left: 340px; }
> .offset-two-thirds { margin-left: 660px; }
My guess is that it's something small, any help would be appreciated!
It is something small.
You're missing a doctype. Add as the very first line:
<!DOCTYPE html>
Without a valid doctype, your page is displayed in quirks mode.
Open the Developer Tools (press F12) to see which mode is actually being used.
Also sometimes you have to override group policies that may force IE into non compatibility mode. We have to do this at my organization because group policies force this mode on the intranet.
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
I had a similar issue with Bootstrap 2.2.1. It looked great in IE 9 where I was developing it. However, one of the users is on IE 7 (don't ask, ugh) and for the most part the header was not showing up correctly. The solution was to change all of the HTML 5 tags (header, footer, article and section) to divs. That did the trick for me.
I had tried just doing the above suggestions with DOCTYPE and such but nothing totally worked for me until that.

Resources