SCSS target classes and pseudo selectors simultaneously - css

I'm writing a library and I'd like to style all buttons.
HTML
<div>
<p>Buttons</p>
<button>Button</button>
<button class="r1">Button</button>
</div>
<div>
<p>File inputs</p>
<input type="file" />
<input type="file" class="r1" />
</div>
SCSS
button,
input[type=file]::file-selector-button {
background: #81ecec;
border: 2px solid #00cec9;
&.r1{
background: red;
}
}
This code processes to:
button.r1,
input[type=file]::file-selector-button.r1 {
background: red;
}
[This is invalid and does not work]
Is there a mixin or method I can use so that I can place the classes on only the parent selector, without this getting out of hand? I intend to have multiple classes (primary, secondary, large, small) and I don't want to write:
button.r1,
input[type=file].r1::file-selector-button{
...
}
button.large,
input[type=file].large::file-selector-button{
...
}
button.small,
input[type=file].small::file-selector-button{
...
}
I can't figure out a good way of targeting the parent input[type="file"]
This codepen has the first example in it, and as it isn't valid CSS the background: red doesn't take effect:
https://codepen.io/EightArmsHQ/pen/VwxwPGM/139933ae274200149b84afdb726478c5?editors=1100
Attempt 1
At the moment I am using a mixin like so:
#mixin button{
background: var(--button-primary);
color: #fff;
text-decoration: none;
border: none;
display: inline-block;
padding: 4px 8px;
}
#mixin button-r1{
border-radius: 3px;
}
button,
.button,
input[type="submit"],
input[type="reset"]{
#include button;
&.r1{
#include button-r1;
}
}
input[type=file]{
&::file-selector-button{
#include button;
}
&.r1::file-selector-button{
#include button-r1;
}
}
The benefit is that I don't need to repeat the same styles over and over, however I feel like there must be a better way of creating a mixin that interpolates a class somehow.
Attempt 2
Using the classname as an argument works well, however I lose the ability to nest the rules, which is a shame and one of my favourite parts of SCSS.
#mixin buttonAndFileInputs($classname: "") {
button#{$classname},
.button#{$classname},
input[type="submit"]#{$classname},
input[type="reset"]#{$classname},
input[type="file"]#{$classname}::file-selector-button {
#content;
}
}
#include buttonAndFileInputs {
background: var(--button-primary);
color: #fff;
}
#include buttonAndFileInputs(".r1") {
border-radius: 3px;
}

I'm not 100% clear on what you're trying to do
But I think if you edit your codepen to this scss
button,
input[type=file] {
background: #81ecec;
border: 2px solid #00cec9;
&.r1{
background: red;
}
}
::file-selector-button {
background: inherit;
border: inherit;
}
that will get what you're looking for
Edit to add explanation:
This will make the file-selector-button follow the background and border properties of the input[type=file].
This means that the file-selector-button will match the rest of the input background.

Related

SCSS ampersand not working when trying to make modifiers for class names [duplicate]

I'd like to implement something like the BEM model in my Sass library. But I'm struggling to find a clean way to do this.
For example, I'd like to declare a 'base' style for a common element, and then extend it with useful variations:
.container {
margin: 10%;
background: #eee;
&-featured {
border: 2px solid #999;
}
}
The problem here is that the generated .container-featured class only contains the border property—Sass doesn't include the margin and background from its 'parent' class.
So you end up having to double up on classes in your markup to get the desired results:
<div class="container container-featured">
...
</div>
Is there some way to pull the properties from a parent class down into that modifier class, so you can get the same visual result just referencing the modifier class in your markup?
<div class="container-featured">
<!-- has margin, background, and border styles via just modifier class -->
</div>
I've tried using mixins to do this, but things get verbose and repetitive very quickly:
#mixins container {
margin: 10%;
background: #eee;
}
.container {
#include container;
&-featured {
#include container;
border: 2px solid #999;
}
}
Is there a simple, clean way of achieving this with Sass?
What you are looking for is the #extend directive. #extend allows you share a set of CSS properties from one selector to another. This means that you would only need to use the container-featured class.
Example
.container {
margin: 10%;
background: #eee;
&-featured {
#extend .container;
border: 2px solid #999;
}
}
compiles to:
.container,
.container-featured {
margin: 10%;
background: #eee;
}
.container-featured {
border: 2px solid #999;
}
You should use mixin in BEM not in Sass!
Mixins are just that - usage of several blocks and/or elements on the same DOM node.
A single DOM node can represent:
several blocks b-menu b-head-menu
a block and an element of the same block b-menu b-menu__layout
a block and an element of another block b-link b-menu__link
elements of different blocks b-menu__item b-head-menu__item
a block with a modifier and another block b-menu b-menu_layout_horiz b-head-menu
several different blocks with modifiers b-menu b-menu_layout_horiz b-head-toolbar b-head-toolbar_theme_black
Read more at: http://bem.github.io/bem-method/html/all.en.html, section Mixin.
Also you can use i-blocks (abstract blocks), so your .container will be .i-container, read more: http://bem.github.io/bem-method/html/all.en.html, section Naming conventions.
And with Sass you can implement i-block as
<div class="container-featured">
...
</div>
%i-container {
// abstract block styles
margin: 10%;
background: #eee;
}
.container-featured {
#extend %i-container;
border: 2px solid #999;
}
Without Sass, mixin in the BEM are made as follows:
<div class="i-container container-featured">
...
</div>
.i-container {
// abstract block styles
margin: 10%;
background: #eee;
}
.container-featured {
border: 2px solid #999;
}

Flat QPushButton, background-color doesn't work

I created QPushButton in Qt Designer with this stylesheet:
QPushButton#pushButton {
background-color: #ffffff;
}
QPushButton#pushButton:disabled {
background-color: yellow;
}
QPushButton#pushButton:pressed {
background-color: orange;
}
QPushButton#pushButton:focus:pressed {
background-color: black;
}
QPushButton#pushButton:focus {
background-color: green;
}
QPushButton#pushButton:hover {
background-color: red;
}
QPushButton#pushButton:checked {
background-color: pink;
}
It Works, but when i check "flat" in the properties, then it doesn't work anymore, I would like to ask you why? And how can i do it, if i need flat QPushButton ?
For the second part of your question: Don't use the "flat" property, but modify your stylesheet to achieve a flat look, perhaps like this:
QPushButton#pushButton {
background-color: #ffffff;
border: 0px;
}
/* ... plus the rest of your stylesheet ... */
Concerning the "why doesn't it work" part? In my experience, mixing stylesheets and non-stylesheet-options for widgets yields many mysterious effects that are hard to explain. I have given up asking for the "why"s.
// Send Button
m_send_button = new QPushButton("Send", this);
m_send_button->setFlat(true);
m_send_button->setStyleSheet(QString::fromUtf8("QPushButton:flat {"
"color: #FFFFFF;"
"border: 0px;" // or border: none;
"background-color: #F39200;"
"}"));

fail to change placeholder color with Bootstrap 3

Two questions:
I am trying to make the placeholder text white. But it doesn't work. I am using Bootstrap 3. JSFiddle demo
Another question is how do I change placeholder color not globally. That is, I have multiple fields, I want only one field to have white placeholder, all the others remain in default color.
html:
<form id="search-form" class="navbar-form navbar-left" role="search">
<div class="">
<div class="right-inner-addon"> <i class="icon-search search-submit"></i>
<input type="search" class="form-control" placeholder="search" />
</div>
</div>
</form>
css:
.right-inner-addon {
position: relative;
}
.right-inner-addon input {
padding-right: 30px;
background-color:#303030;
font-size: 13px;
color:white;
}
.right-inner-addon i {
position: absolute;
right: 0px;
padding: 10px 12px;
/* pointer-events: none; */
cursor: pointer;
color:white;
}
/* do not group these rules*/
::-webkit-input-placeholder { color: white; }
FF 4-18
:-moz-placeholder { color: white; }
FF 19+
::-moz-placeholder { color: white; }
IE 10+
:-ms-input-placeholder { color: white; }
Assign the placeholder to a class selector like this:
.form-control::-webkit-input-placeholder { color: white; } /* WebKit, Blink, Edge */
.form-control:-moz-placeholder { color: white; } /* Mozilla Firefox 4 to 18 */
.form-control::-moz-placeholder { color: white; } /* Mozilla Firefox 19+ */
.form-control:-ms-input-placeholder { color: white; } /* Internet Explorer 10-11 */
.form-control::-ms-input-placeholder { color: white; } /* Microsoft Edge */
It will work then since a stronger selector was probably overriding your global. I'm on a tablet so i cant inspect and confirm which stronger selector it was :) But it does work I tried it in your fiddle.
This also answers your second question. By assigning it to a class or id and giving an input only that class you can control what inputs to style.
There was an issue posted here about this: https://github.com/twbs/bootstrap/issues/14107
The issue was solved by this commit: https://github.com/twbs/bootstrap/commit/bd292ca3b89da982abf34473318c77ace3417fb5
The solution therefore is to override it back to #999 and not white as suggested (and also overriding all bootstraps styles, not just for webkit-styles):
.form-control::-moz-placeholder {
color: #999;
}
.form-control:-ms-input-placeholder {
color: #999;
}
.form-control::-webkit-input-placeholder {
color: #999;
}
A Possible Gotcha
Recommended Sanity Check - Make sure to add the form-control class to your inputs.
If you have bootstrap css loaded on your page, but your inputs don't have the
class="form-control" then placeholder CSS selector won't apply to them.
Example markup from the docs:
I know this didn't apply to the OP's markup but as I missed this at first and spent a little bit of effort trying to debug it, I'm posting this answer to help others.
I'm using Bootstrap 4 and Dennis Puzak's solution does not work for me.
The next solution works for me
.form-control::placeholder { color: white;} /* Chrome, Firefox, Opera*/
:-ms-input-placeholder.form-control { color: white; } /* Internet Explorer*/
.form-control::-ms-input-placeholder { color: white; } /* Microsoft Edge*/
Bootstrap has 3 lines of CSS, within your bootstrap.css generated file that control the placeholder text color:
.form-control::-moz-placeholder {
color: #999999;
opacity: 1;
}
.form-control:-ms-input-placeholder {
color: #999999;
}
.form-control::-webkit-input-placeholder {
color: #999999;
}
Now if you add this to your own CSS file it won't override bootstrap's because it is less specific. So assmuning your form inside a then add that to your CSS:
form .form-control::-moz-placeholder {
color: #fff;
opacity: 1;
}
form .form-control:-ms-input-placeholder {
color: #fff;
}
form .form-control::-webkit-input-placeholder {
color: #fff;
}
Voila that will override bootstrap's CSS.
The others did not work in my case (Bootstrap 4). Here is the solution I used.
html .form-control::-webkit-input-placeholder { color:white; }
html .form-control:-moz-placeholder { color:white; }
html .form-control::-moz-placeholder { color:white; }
html .form-control:-ms-input-placeholder { color:white; }
If we use a stronger selector (html first), we don't need to use the hacky value !important.
This overrides bootstraps CSS as we use a higher level of specificity to target .form-control elements (html first instead of .form-control first).
I think qwertzman is on the right track for the best solution to this.
If you only wanted to style a specific placeholder, then his answer still holds true.
But if you want to override the colour of all placeholders, (which is more probable) and if you are already compiling your own custom Bootstrap LESS, the answer is even simpler!
Override this LESS variable:
#input-color-placeholder
Boostrap Placeholder Mixin:
#mixin placeholder($color: $input-color-placeholder) {
// Firefox
&::-moz-placeholder {
color: $color;
opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526
}
&:-ms-input-placeholder { color: $color; } // Internet Explorer 10+
&::-webkit-input-placeholder { color: $color; } // Safari and Chrome
}
now call it:
#include placeholder($white);
You should check out this answer : Change an HTML5 input's placeholder color with CSS
Work on most browser, the solution in this thread is not working on FF 30+ for example
With LESS the actual mixin is in vendor-prefixes.less
.placeholder(#color: #input-color-placeholder) {
...
}
This mixin is called in forms.less on line 133:
.placeholder();
Your solution in LESS is:
.placeholder(#fff);
Imho the best way to go. Just use Winless or a composer compiler like Gulp/Grunt works, too and even better/faster.

Is it better to chain CSS classes or name them separately for modular purposes?

For example, which is better:
Method 1 (name classes separately):
/* CSS */
.textbox-red,
.textbox-green {
padding: 10px;
border: 1px solid #CCC;
border-radius: 10px;
}
.textbox-red { color: #900; }
.textbox-green { color: #3c3; }
/*HTML*/
<div class="textbox-red"></div>
<div class="textbox-green"></div>
OR ------------
Method 2 (chain classes):
/* CSS */
.textbox {
padding: 10px;
border: 1px solid #CCC;
border-radius: 10px;
}
.textbox.text-red { color: #900; }
.textbox.text-green { color: #3c3; }
/*HTML*/
<div class="textbox text-red"></div>
<div class="textbox text-green"></div>
What is a better practice among the two?
My opinion is that you should use modular css -
You could also combine classes instead of linking them:
/*CSS*/
.textbox {
padding: 10px;
border: 1px solid #CCC;
border-radius: 10px;
}
.text-red { color: #900; }
.text-green { color: #3c3; }
/*HTML*/
<div class="textbox text-red"></div>
<div class="textbox text-green"></div>
That way you can reuse the red and green colors in cases when you want to have a red background without a textbox. This way you can re-use your code more and you have a loose coupling between your textbox and text-color
I personally would go with method 2. That way you can swap out text-red or text-green easily for text-blue or text-yellow and still keep the underlying style for your text. Basically, method 2 allows for more flexibility and maintainability, IMHO.
In my experience the modular approach gives you the most flexibility. The modular css pattern is also used in Twitter Bootstrap where flexibility is very important.
First better if you making style for IE6, because this browser dont support second method.

Scoping sass variable

Is there a way to add scope to sass variables?
I want to be able to attach a class to my body element. The class will refer to a set of colours that the rest of the stylesheets can access.
I have tried:
#mixin theme_one{
$color: #000;
}
.theme_one{
#include theme_one;
}
and
.theme_one{
$color: #000;
}
I've just come across the same issue myself. I wanted to have different colour themes for different sections of my site.
Using a mixin seems like the best way to go. It's nicely DRY, and easy to use. The trick is not setting your colours in your main styles blocks, but rather using only the mixin for this.
I've set up the theme colours as variables at the top so they can be edited nicely, and I've set them as lists so that multiple values can be passed without hordes of variable being defined.
So:
// Variable Definitions
$defaultColor: black white grey;
$color2: blue green brown;
$color3: red white blue;
#mixin colorSet($color: $defaultColor) {
$link: nth($color, 1);
$border: nth($color, 2);
$background: nth($color, 3);
border-color: $border;
background-color: $background;
.column {
border-color: lighten($border, 10%);
}
a {
color: $link;
&:hover {
color: darken($link, 15%);
}
}
}
// Default colours
body {
#include colorSet();
}
// Scoped colours
.my-theme-3 {
#include colorSet($color3);
}
.my-theme-2 {
#include colorSet($color2);
}
Will produce something like this:
body {
border-color: white;
background-color: grey; }
body .column {
border-color: white; }
body a {
color: black; }
body a:hover {
color: black; }
.my-theme-3 {
border-color: white;
background-color: blue; }
.my-theme-3 .column {
border-color: white; }
.my-theme-3 a {
color: red; }
.my-theme-3 a:hover {
color: #b30000; }
.my-theme-2 {
border-color: green;
background-color: brown; }
.my-theme-2 .column {
border-color: #00b300; }
.my-theme-2 a {
color: blue; }
.my-theme-2 a:hover {
color: #0000b3; }
Edit: Updated to use default mixin values.
In your case no need to use mixin, If you have set of many styles then use mixin,
ie. if you have
#mixin theme_one{
$color: #000;
height: 50px;
}
then use Mixin
otherwise for single property use only variable
$color: #fff;
.some_class01{
color: $color;
background: $color;
}
.some_class22{
border-color: $color;
}
IMP: Variable should assign at the top of your code, it means don't use it after/below where you assigned it :)
Not sure if this is what you are looking for. It looks like you may have tried something similar to this,
which should probably work. (it may just be a matter of using !default)
Your body tag with a class on it..
<body class="theme_one">
</body>
Sass variables defined in stylesheet..
//THEME ONE VARIABLES
.theme_one{
$borderColor:#333 !default;
$fontColor:#999 !default;
}
//THEME TWO VARIABLES
.theme_two{
$borderColor:#CCC !default;
$fontColor:#000 !default;
}
Pre-existing CSS which will be overwritten depending on which class is used on the body tag.
h1.someheader {
color:$fontColor;
border-bottom:1px solid;
border-color:$borderColor;
}
Otherwise you could maybe try something like this. It looks like you may have tried something similar, however there seems to be an error with your mixin ... see note below.
//mixin used to set variables for properties
#mixin themeOne($fontColor,$borderColor) {
color:$fontColor;
border-color:$borderColor;
}
#include themeOne(#000,#CCC);
Pre-existing CSS
h1.someheader {
color:$fontColor
border-color:$borderColor;
border-bottom:1px solid;
}
Also note in your mixin example you are using $color:#000; ... This won't be interpreited properly as it should be color:#000; You can't use variables as selectors
unless you do something like #{$color}:#000;
I haven't quite tested this yet, so some things might need to be adjusted. If this doesn't solve your problem I hope it at least gives you some ideas.

Resources