Tailwind downsidesand where it disappoints
In Tailwind, sizes for fonts and other characteristics are written in rems. If you don't like to use rems when a design is built on pixels (see more on this here), rems values can be calculated automatically with a helper pxToRemPair which can also use the body font size, but if the body font size for mobile is smaller than the desktop one, that helper will not know about it, so the generated rem size will not be precise on mobile because it will still use the body font size from desktop, not having the possibility to reuse pxToRemPair helper for a smaller screen size with different values. See bellow how to use
const ( pxToRemPair: pxToRemPairHelper ) = require('@captaincss/captaincss/helpers');
const baseFontSize = 18; //Is no way to change the base font size as 16 for mobile
const pxToRemPair = (px) => {
return pxToRemPairHelper(px, baseFontSize);
}
module.exports = {
theme: {
fontSize: {
...pxToRemPair(16)
}
}
}
Another way is to add the font size in a variable.css file as
@layer base{
--font-size-md: 1rem;
}
and for @screen sm{} to recalculate the rems as per a smaller base font. As 18px font size for desktop and 16px for mobile.
The downside of this, which is actually not eliminating the problem of having rem sizes recalculated based on different base font sizes (mobile/desktop), is that if the client is asking for the base font to be decreased for small/mobile screens with a number of points, all the rems values will have to be recalculated manually.
In the same time, having values written in rems will make a difficult process to confirm if a rem value is in concordance with the design, which has the sizes always in pixels.
Another downside of using variables from variables.css (imported in main.css as @import url("./components/_fundation.css");) written as
@layer base {
:root {
--font-size-md: 1rem; /*desktop base font size or 18px*/
@screen sm {
--font-size-md: 1rem; /*mobile base font size or 16px*/
}
}
}
and then used in tailwind.config.cjs as
fontSize: {
md: ['var(--font-size-md)'],
}
is that for a component other than the body, with a font size of 18px on desktop and 16px on mobile, a md size in desktop will be 1rem (18px/18px) and on mobile the same variable named as md of 1rem was calculated based on 16px/16px, which can create confusion for the code reader.
First downside is that because the reduction of the font size was globalised, it will target components where the font size is not intended to downsize on mobile so the whole project is at risk of regressions. In another way said, bugs to be introduced.
Second, the above code is not producing anything more for both screen sizes than
@apply text-md sm:text-md,
which is a lot more easy to read and you don't need to check a config file that is sending you to a variable.css file to see the font size. The above example is part of the Tailwind documentation.
Plus, I miss a mixin from SASS that is actually giving the possibility to use the px size given by a design, in the code, and convert it to rems, using in the same time the base font size.
@function calculateRem($size, $baseSize){
$remSize: $size / $baseSize;
@return $remSize + rem;
}
@mixin font-size($size, $baseSize) {
font-size: $size +px;
font-size: calculateRem($size, $baseSize);
}
The above SASS mixin is showing transparency and is easy to read in the CSS when is used as
@include font-size(18, 18); /* Font size on the element / Base font size -> both in pixels*/
and for small screens is very transparent by doing
@media (max-screen: 1080){
@include font-size(18, 16); /*if the font size is not reduced in the design*/
@include font-size(16, 16); /*if the font size is reduced in the design*/
}
The first 18 can be anything like 22 or 26 and if a 22 is designed to decrease for one component, on mobile, maybe for another component will have to stay the same. If so, what is the point of having all the global declarations in tailwind config, plus the long hard to read chaining for the variables definition and use?
And if you think the naming convention for small as sm, medium as md and large as lg is good, let me ask you what your design is generating? small, medium and large text? A design can have a vast numbers of font sizes (exact numbers) and you can find yourself very fast in the situation where you will create variables like size2Xlg or smExtra and no one will know what that means even looking at the rem size (without a pixel measure). Plus, sm, md, lg and anything else your project will need to cover all the sizes, will be used not just for text size, but also for screens, margins, padding.
Here is a website https://tailwindremconverter.netlify.app/ that is helping with px to rem conversion considering the Base Font Size.
Is also showing that a variable name can be more explicatory named with a number (as a string, because is a name in the end) that can be actually the exact font size if you wish, from the design.
Are you in a project where fonts are named as text-16? Do a search replace in your preferred code editor and replace it with text-md if you wish. Then change in tailwind configs the ...pxToRemPair(16) in md: '1rem' considering your base font size, and you will end having the same thing but much harder to read.
Or better, use it in the CSS as text-18 on desktop and sm:text-16 on mobile and it will generate sizes in rems but when you will read the code you will know exactly what sizes in pixels you are seeing.
The dark side of naming variable with sm, md, lg
Some developers like to create a screen breakpoint for mobiles as sm, and for desktop as lg (large).
These sm and lg will keep different values than the text size, that will also have a sm, and lg value, but under this naming convention you will need, as a front-end developer, to remember that they represent different values for each use case.
Small padding - 1rem. We don't even know if it was translated from a 16px padding in the design and it might not change for mobile if it was used on desktop, but it will still have 'spaces' extended in tailwind config as sm: '1rem' and it will increase the confusion and unclarity.
Why not better add breakpoints as max1080 or min1080? At least you will know up to what point a screen rule is applied when you read the code.
Do you need to reuse a component for another project but a breakpoint of 1080 does not apply, based on the design? Just do a search replace with a new value, in the whole component or project.
Do you think it will be easy for a new developer to get into the above sm, md, lg code with chained setup and unclear rem sizes that do not start from a pixel measure and do fast changes without breaking other things?