[NOTE: Since writing this article, I've put this utility into an NPM package. You can find it here: https://www.npmjs.com/package/@toolz/css3]
When using JavaScript to do inline styling, you can run into several headaches:
Unless you're a Certified CSS Guru, it can occasionally be difficult to remember all of the CSS3 properties that are available to you.
And even if you remember all of the available properties, it can be even more daunting to remember all of the potential static values that are accepted on each of those properties.
For example, if you want to set thecursor
on a given element, there are dozens of potential values. Do you wantmove
orgrab
? And are you sure you're not forgetting a more appropriate value that's available to you?Assuming that you know exactly which CSS3 property you want, and which value you want to assign to that property, you're still susceptible to spelling errors that could render your desired styling moot.
For example, I've done this before:cursor : 'grabing'
.Many of CSS's shorthand properties accept/require free-form text (e.g., the
border
property).
But when you're writing your property, can you always, without fail, spit out the exact syntax that's required for that property?? For example, when writingmargin : '10px 20px 30px 40px'
, is the top margin the second value? The third? It may feel old-hat to you now, but sometimes I still have to carefully read my style attributes to ensure that I haven't juxtaposed my values.Inline styles can leave you devoid of IDE assistance.
If I'm writing a standalone.css
file, my IDE does a pretty damn good job of showing me all of the available options in the autocomplete feature. But once I start using inline styles, the IDE can range from barely-helpful to downright useless.
This Is A Holy-War-Free Zone
Reading the "issues" I've outlined above, you may be sitting back and chortling while you think:
That's why you don't use inline styles!
So let's get one thing out of the way. Inline-vs-class CSS is definitely one of the coding/designing/HTML/CSS/JS Holy Wars. And I'm not writing this post to open that can of worms (I'll go there in another, future post...)
So if you're all smug in the knowledge that you simply do not use inline styles - in any scenario - then... this post is not for you. Seriously. I'd love to see you back on my blog at some future date. Maybe we can have a coffee sometime. But right now, for the rest of this post, we're gonna be catering to the slobbering coding masses who still, for whatever reason, find it appropriate to, at least occasionally, use inline styles.
Have a great day! Hope to see you around soon...
A Useful Little Helper Object
Alright... Are they gone???
Good. It was getting a little crowded in here anyway. Now that we've all got a bit more legroom, let me show you a simple helper object I've created to assist me in my dirty, grimy, inline CSS adventures.
The complete code for my utility can be found here:
https://github.com/bytebodger/javascript-css3-lookup
Don't be afraid. It's, literally, a single JavaScript file (not counting the README.md
). That file's a bit long-ish (cuz it has references for basically all of the CSS3 properties and their accepted values). But there's no real logic in it.
Here's an abbreviated version of what that file contains:
const css3 = {
background : {
inherit : 'inherit',
initial : 'initial',
unset : 'unset',
[`ex: url("bg.jpg") #fff`] : null,
[`ex: url("bg.jpg") 20% 0% repeat-y fixed #fff`] : null,
[`ex: url("bg.jpg") 20% 0% / contain repeat-y fixed content-box padding-box #fff`] : null,
},
dislay : {
block : 'block',
inherit : 'inherit',
initial : 'initial',
inline : 'inline',
inlineBlock : 'inline-block',
inlineTable : 'inline-table',
listItem : 'list-item',
none : 'none',
table : 'table',
tableCaption : 'table-caption',
tableCell : 'table-cell',
tableColumn : 'table-column',
tableColumnGroup : 'table-column-group',
tableFooterGroup : 'table-footer-group',
tableHeaderGroup : 'table-header-group',
tableRow : 'table-row',
tableRowGroup : 'table-row-group',
unset : 'unset',
},
textDecorationStyle : {
dashed : 'dashed',
dotted : 'dotted',
double : 'double',
inherit : 'inherit',
initial : 'initial',
solid : 'solid',
unset : 'unset',
wavy : 'wavy',
},
};
export default css3;
There's more - a lot more - in the full file. But the snippet above will be more than suitable to illustrate how this works. Now here's an example of how this file helps me in my daily coding:
import React from 'react';
import css3 from './css3';
export default class MyComponent extends React.Component {
render = () => {
return (
<div>
Inline styling is Da Bomb!
</div>
);
};
}
This is just a base React component, almost empty. And of course, our container <div>
currently has no styling on it whatsoever. So let's do a little styling...
import React from 'react';
import css3 from './css3';
export default class MyComponent extends React.Component {
render = () => {
return (
<div style={{
textDecorationStyle : css3. // Once I type the '.', my IDE springs into action.
}}
>
Inline styling is Da Bomb!
</div>
);
};
}
As soon as I type css3.
, my IDE recognizes that I'm calling the css3
object and my autocomplete pops up with all the available properties on that object. Of course, textDecorationStyle
is one of the properties on that object. So as soon as I type a few more letters, drilling down into t
, then e
, then x
(etc.), my IDE quickly narrows down on the textDecorationStyle
property.
That will eventually get me to here:
import React from 'react';
import css3 from './css3';
export default class MyComponent extends React.Component {
render = () => {
return (
<div style={{
textDecorationStyle : css3.textDecorationStyle. // My IDE springs back into action!
}}
>
Inline styling is Da Bomb!
</div>
);
};
}
Once it's clear that I've chosen the textDecorationStyle
property, and I again type a .
, my IDE's autocomplete pops up again. This time, it helpfully shows me all of the potential properties that exist on css3.textDecorationStyle
.
I find this to be tremendously useful and time-saving. To be perfectly frank, even with 20+ of web development experience under my belt, I don't think I knew until today (!) that wavy
was even an option on the textDecorationStyle
CSS property. But with this little utility, I don't need to memorize all that minutiae. It's right there in front of me, staring at me from the autocomplete, any time I type css3.textDecorationStyle.
In the past, when I was thinking, "Hmm... this particular bit of text really needs to be styled differently," I would have had to reference the third lobe of my brain (a.k.a. Google). I woulda searched for "css text decoration style" and, in the worst-case scenario, I might have even felt compelled to browse through several sites looking for just the right option. And as powerful as Google/Stack Overflow/etc can be - they're also potential distractions. So anything that keeps my eyes in the code is a good thing.
When I'm done, the code looks like this:
import React from 'react';
import css3 from './css3';
export default class MyComponent extends React.Component {
render = () => {
return (
<div style={{
textDecorationStyle : css3.textDecorationStyle.wavy,
}}
>
Inline styling is Da Bomb!
</div>
);
};
}
Sure, css3.textDecorationStyle.wavy
is more verbose than just using 'wavy'
. But the lookup process was swift. Any other developer looking at this code should be able to see, through nothing more than plain reading, what's happening. And I have the added bonus of knowing that it was impossible for me to misspell "wavy".
(If you think it's impractical to imagine that anyone could misspell "wavy", then congratulations. You're not old like me. You have the unbridled confidence of youth. Enjoy it. While it lasts...)
Also, if it's really bugging you to see that "long" css3.textDecoration.wavy
value in the <div>
's style, you're always welcome to deconstruct it. In theory, after thorough deconstruction, you could end up with a line that looks like this:
textDecorationStyle : wavy,
If I want to force my <div>
to display inline, that would look like this:
import React from 'react';
import css3 from './css3';
export default class MyComponent extends React.Component {
render = () => {
return (
<div style={{
display: css3.display.inline,
textDecorationStyle : css3.textDecorationStyle.wavy,
}}
>
Inline styling is Da Bomb!
</div>
);
};
}
Finally, let's add a background to that <div>
. This process will be a bit more... manual than the first two properties. Because the background
property is a shorthand property. It allows us to chunk several different CSS values onto a single line.
Unfortunately, I know of no way to craft a helper object that will allow us to swiftly pick-and-choose the appropriate value for a shorthand property from a list. There are an infinite number of potential combinations. But even in that scenario, the css3
object can still provide us with some assistance.
When I go back into the React class and type:
background : css3.background.
The autocomplete will, once again, spring into action. This time, it will only be able to give us suggestions. There are three standard properties under background
: inherit
, initial
, and unset
. But those are basically universal "default" properties that will do nothing to help me define the background
the way I want.
But the css3
object does give us at least some "guidance" on typing the value. Right in the IDE's autocomplete function, there will be three "example" properties. Those properties aren't really meant to be chosen (which is why their values are set to null
). But they do demonstrate the various syntaxes that are available to properly complete that value.
So after seeing these "helper syntaxes" in the css3
autocomplete options, I finish the demo component as such:
import React from 'react';
import css3 from './css3';
export default class MyComponent extends React.Component {
render = () => {
return (
<div style={{
background : 'url("someImage.png") repeat-y #ddd',
display: css3.display.inline,
textDecorationStyle : css3.textDecorationStyle.wavy,
}}
>
Inline styling is Da Bomb!
</div>
);
};
}
And when I'm trying to crank out some React/Angular/JavaScript/whatever code, having that built-in utility helps me to avoid a lot of extraneous Googling.
Top comments (8)
Cool writeup. It is similar to how we normally handle any other strings that need to be used in multiple places (theme related stuff, event names, enums etc.) - dy defining constants.
Some random thoughts:
Thanks again for the thoughtful feedback!
You're absolutely right that, when you boil it down, this is just a basic shared constant. I'm just amazed/annoyed sometimes when I realize that there are no "pre-baked" constants for the important shit that I find myself googling over and over and over...
Totally agree about the inline-styling necessities (at times). I put that Holy War caveat in the article because, amongst some people, you simply cannot have an intelligent conversation about inline styles (especially, in React) without some pedantic jerk trying to shout you down. There's a whole other article on the horizon about this exact topic... One of my favorite (and simplest) justifications for inline React styles something like this:
display : someCondition ? 'inherit' : 'none'
. There's just no way that I'm gonna try to pack that away into two conditional CSS classes.Good point about bundle size. I will freely admit that, more often than not, I pay this little attention, because in today's high-bandwidth environment, I feel that this is usually a "micro-optimization". But that's not meant to discount your accurate observation. Like any other library/class/utility that is providing nothing more than syntactic convenience, it's always a good idea to at least be aware of the cost in package size.
BTW, I do agree with the problem statement :)
I forgot to say in the original comment.
Remembering all of these css attributes and values and what they all do is like trying to memorize an encyclopedia.
One more note on bundle size. If I were to put this into a proper NPM "package", I could create
deploy
hooks that would essentially empty out the lookup class and replace the code with the raw text/number values for the CSS properties. But, for the time being, that kinda feels like overkill and I don't have the time to dive into that...Another interesting option might be an IDE plug-in.
It could also maybe provide some documentation for each attribute/ value on the fly.
But yhea.. probably an overkill :)
Maybe something like
marketplace.visualstudio.com/items...
Ideally, the plugin would be configurable, so you could drop in any object that would serve as a kinda "definition file". It could then be used in your autocompletes without needing to be bundled into the code itself.
It should be configurable, because even if this plugin worked beautifully, I'd hate to have to write another plugin (or find another one out there on the interwebs) the next time I have another set of commonly-used constants that I want to autocomplete.
For the record, VS Code does this without the helper, thanks to React's type declarations.