Can I use Tailwind's media query variants in PostCSS? - tailwind-css

Tailwind provides responsive utility variants sm, md, lg, xl and 2xl, and you can define your own as well.
I can use them in class names:
<img class="w-16 md:w-32" src="...">
But can I also use them in PostCSS?
For example, I'm hoping to do something like this (the code doesn't actually work):
img {
#apply w-16;
/* I want this section to apply whenever the `md` media query applies. */
md:& {
#apply w-32;
}
}

Yes you can do it with #screen directive or screen() function
img {
#apply w-16;
#screen md {
#apply w-32;
}
}
img {
#apply w-16;
#media screen(md) {
#apply w-32;
}
}
Sometimes Tailwind may yelling about not supported nested syntax (depends on your PostCSS config or Preprocessor like Less) so you may change code a little
img {
#apply w-16;
}
#screen md {
img {
#apply w-32;
}
}
Finally nothing stops you from using variants within #apply if you wish
img {
#apply w-16 md:w-32;
}

Related

Can I use a Bootstrap class as a variable in a custom CSS rule?

To make my website responsive, I was going to use media queries to change the text size, etc. The problem is that I use bootstrap to set the sizes for the text. I was wondering if there was a way to use the classes from the bootstrap in my CSS file.
For example, something like:
.test {
font-size: display-5; /* display-5 is a bootstrap defined size */
}
I originally thought I could do this using an #import rule but it didn't work.
How would I go about doing this?
What i would do, is instead of relying on bootstrap, i would just do manual media queries instead like below
<div>
<p class="fontSizeClass">Your text here</p>
</div>
with the css being
#media screen and (max-width: 600px) {
.fontSizeClass {
font-size: 30px;
}
}
#media screen and (min-width: 601px) {
.fontSizeClass {
font-size: 80px;
}
}
bootstrap has sizes listed here:
sm `min-width > 576;`
md `min-width > 768;`
lg `min-width > 992;`
xl `min-width > 1200`
xxl `min-width > 1400`

Globally change font size in Vuetify based on viewport? [duplicate]

In vuetify they have helper classes for typography.
for example, .display-4 goods for h1. here the full list.
When I choose display-1 for some element, In all resolutions the class gets the same font size (34px).
I was expecting to:
.display-4 will have font size of 34px in screen wide of 1024px.
.display-4 will have font size of 18px in screen wide of 300px.
According to this I have two questions, why is that? and how to make my font size elements be responsive using vuetify?
Update
Vuetify version 1.5
Take a look at display helpers example to see how to use a class when hitting a breakpoint. That being said, you can use dynamic class binding and breakpoint object in Vuetify.
Example:
:class="{'subheading': $vuetify.breakpoint. smAndDown, 'display-2': $vuetify.breakpoint. mdAndUp}"
Vuetify version 2
breakpoint object
Display
My solution changes font-sizes globally in the variables.scss file:
This is assuming you're using Vuetify 2 and #vue/cli-service 3.11 or later.
Step 1:
In src/scss/ create _emptyfile.sass and _font-size-overrides.scss.
In the _emptyfile.sass you can add this comment:
// empty file to workaround this issue: https://github.com/vuetifyjs/vuetify/issues/7795
Step 2:
In the _font-size-overrides.scss file:
/**
* define font-sizes with css custom properties.
* you can change the values of these properties in a media query
*/
:root {
--headings-size-h1: 28px;
--headings-size-h2: 22px;
#media #{map-get($display-breakpoints, 'lg-and-up')} {
--headings-size-h1: 32px;
--headings-size-h2: 26px;
}
}
Step 3:
In the variables.scss file (where you override the Vuetify variables):
/**
* Override Vuetify variables as you normally would
* NOTE: remember to provide a fallback for browsers that don't support Custom Properties
* In my case, I've used the mobile font-sizes as a fallback
*/
$headings: (
'h1': (
'size': var(--headings-size-h1, 28px),
),
'h2': (
'size': var(--headings-size-h2, 22px),
)
);
Step 3:
In the vue.config.js file:
module.exports = {
css: {
loaderOptions: {
sass: {
prependData: `#import "#/scss/_emptyfile.sass"` // empty file to workaround this issue: https://github.com/vuetifyjs/vuetify/issues/7795
},
scss: {
prependData: `#import "#/scss/variables.scss"; #import "#/scss/_font-size-overrides.scss";`,
}
}
},
};
font-sizes globally in the variables.scss file
html {
font-size: 90%;
#media only screen and (min-width: 600px) {
font-size: 94%;
}
#media only screen and (min-width: 1000px) {
font-size: 98%;
}
#media only screen and (min-width: 1200px) {
font-size: 100%;
}
}

Why #screen xl and #screen lg gets overridden by #screen md in tailwindcss?

I extended tailwind margin properties in the config file:
module.exports = {
theme: {
extend: {
'margin': {
'1/5': '20%',
'1/4': '25%',
'1/3': '33.333333%'
}
}
},
variants: {
margin: ['responsive']
},
plugins: []
}
And then applied it in my css with the following:
#screen xl {
.content-section.contract {
#apply ml-1/5;
}
}
#screen lg {
.content-section.contract {
#apply ml-1/4;
}
}
#screen md {
.content-section.contract {
#apply ml-1/3;
}
}
But instead of getting the margin-left: 20% on extra large screens and margin-left: 25% on large screens, styles gets overridden by the value for medium screens.
I tried adding !important in each styles in different screen sizes but it doesn't work as I expected. I believe this cannot be reproduce in a fiddle, since customize utilities is not supported in CDN version of tailwindcss.
According to the image, the order of the queries is responsible for this behavior.
This is because whenever multiple css rules of the same priority apply to an element the last one wins.
In this case here: whenever a screen size reaches the width required by the xl query, the queries for the smaller screens apply as well. Since the medium query is the last one, it overrides the styles of the queries that have been declared before.
A rule of thumb is to sort the queries from smallest to largest when using min-width (mobile first).
When using max-width (desktop first), it is the other way round.
The solution here is to either use max-width instead of min-width or change the order of your queries, so the smallest screen comes first and the largest last.
Example (reversed order):
#screen md {
.content-section.contract {
#apply ml-1/3;
}
}
#screen lg {
.content-section.contract {
#apply ml-1/4;
}
}
#screen xl {
.content-section.contract {
#apply ml-1/5;
}
}

Generic String Setting via CSS / SASS

Is there some type of value that can be assigned any arbitrary string using CSS? For example, "large" or "small".
My purpose is to watch a generic div with display: none and change this as-of-yet-unknown type of value "large" or "small" via a media query. Javascript will watch for this change and use the assigned value.
Example HTML:
<div class="state"/>
Example corresponding SASS:
.state {
#media #{$isSmall} {
unknown-type-of-value: "small";
}
#media #{$isLarge} {
unknown-type-of-value: "large";
}
}
You can't change the value of a <div> with CSS, but you can use :after to have css "append" text to it.
Something like
#media screen{
div.test:after{
content: "small";
}
}
#media print{
div.test:after{
content: "large";
}
}
DEMO: http://jsbin.com/edirad/1 (try to print it, and look at the preview)

Extending selectors from within media queries with Sass

I have an item class and a compact "modifier" class:
.item { ... }
.item.compact { /* styles to make .item smaller */ }
This is fine. However, I'd like to add a #media query that forces the .item class to be compact when the screen is small enough.
On first thought, this is what I tried to do:
.item { ... }
.item.compact { ... }
#media (max-width: 600px) {
.item { #extend .item.compact; }
}
But this generates the following error:
You may not #extend an outer selector from within #media. You may only
#extend selectors within the same directive.
How would I accomplish this using SASS without having to resort to copy/pasting styles?
The simple answer is: you can't because Sass can't (or won't) compose the selector for it. You can't be inside of a media query and extend something that's outside of a media query. It certainly would be nice if it would simply take a copy of it instead of trying to compose the selectors. But it doesn't so you can't.
Use a mixin
If you have a case where you're going to be reusing a block of code inside and outside of media queries and still want it to be able to extend it, then write both a mixin and an extend class:
#mixin foo {
// do stuff
}
%foo {
#include foo;
}
// usage
.foo {
#extend %foo;
}
#media (min-width: 30em) {
.bar {
#include foo;
}
}
Extend the selector within a media query from the outside
This won't really help your use case, but it is another option:
%foo {
#media (min-width: 20em) {
color: red;
}
}
#media (min-width: 30em) {
%bar {
background: yellow;
}
}
// usage
.foo {
#extend %foo;
}
.bar {
#extend %bar;
}
Wait until Sass lifts this restriction (or patch it yourself)
There are a number of ongoing discussions regarding this issue (please don't contribute to these threads unless you have something meaningful to add: the maintainers are already aware that users desire this functionality, it's just a question of how to implement it and what the syntax should be).
https://github.com/sass/sass/issues/1050
https://github.com/sass/sass/issues/456
For the record, here is how I ended up solving the problem with only duplicating generated styles once:
// This is where the actual compact styles live
#mixin compact-mixin { /* ... */ }
// Include the compact mixin for items that are always compact
.item.compact { #include compact-mixin; }
// Here's the tricky part, due to how SASS handles extending
.item { ... }
// The following needs to be declared AFTER .item, else it'll
// be overridden by .item's NORMAL styles.
#media (max-width: 600px) {
%compact { #include compact-mixin; }
// Afterwards we can extend and
// customize different item compact styles
.item {
#extend %compact;
/* Other styles that override %compact */
}
// As shown below, we can extend the compact styles as many
// times as we want without needing to re-extend
// the compact mixin, thus avoiding generating duplicate css
.item-alt {
#extend %compact;
}
}
I believe SASS/SCSS does not support the #extend directive inside of a media query. http://designshack.net/articles/css/sass-and-media-queries-what-you-can-and-cant-do/
You might need to use a mixin instead, though the code bloat needs to be weighed against your objective.
This is the cleanest, partial solution I've found. It takes advantage of #extend where possible and falls back to mixins when inside media queries.
Cross-Media Query #extend Directives in Sass
See the article for full details but the gist is that you call a mixin 'placeholder' that then decides whether to output #extend or an #include.
#include placeholder('clear') {
clear: both;
overflow: hidden;
}
.a {
#include _(clear);
}
.b {
#include _(clear);
}
.c {
#include breakpoint(medium) {
#include _(clear);
}
}
Ultimately it may not be better than just using mixins, which is currently the accepted answer.
I use breakpoints, but it's the same idea:
#mixin bp-small {
#media only screen and (max-width: 30em) {
#content;
}
How to use it:
.sidebar {
width: 60%;
float: left;
#include bp-small {
width: 100%;
float: none;
}
}
There is a text about mixins where you can find out more about this option.
Could you restructure?
.compact { //compact-styles }
.item {}
.item.compact { #extend .compact }
#media (max-width: 600px) {
.item { #extend .compact; }
}
If I understand the documentation correctly, that should work. I think the reason the way you're trying won't work is that it doesn't see .item.compact when it's parsing the #extend, but that's an uninformed guess, so take that with a truck load of salt! :)

Resources