prettier icon indicating copy to clipboard operation
prettier copied to clipboard

[CSS] single line property formatting

Open o-t-w opened this issue 6 years ago • 75 comments

I am re-raising this issue. I am currently working on a CSS utility library. Almost all the classes have a single CSS property, yet they are all formatted by Prettier to take up multiple lines. For a single property, this is a massive waste of space and far less readable.

e.g. here is some code from the relatively popular [Tachyons library](e.g.: https://github.com/tachyons-css/tachyons/blob/master/css/tachyons.css):

.mt0 { margin-top: 0; }
.mt1 { margin-top: .25rem; }
.mt2 { margin-top: .5rem; }
.mt3 { margin-top: 1rem; }
.mt4 { margin-top: 2rem; }
.mt5 { margin-top: 4rem; }
.mt6 { margin-top: 8rem; }
.mt7 { margin-top: 16rem; }

Here's is what it looks like after using Prettier:

.mt0 {
  margin-top: 0;
}
.mt1 {
  margin-top: 0.25rem;
}
.mt2 {
  margin-top: 0.5rem;
}
.mt3 {
  margin-top: 1rem;
}
.mt4 {
  margin-top: 2rem;
}
.mt5 {
  margin-top: 4rem;
}
.mt6 {
  margin-top: 8rem;
}
.mt7 {
  margin-top: 16rem;
}

It is clear to me which one is preferable! Please reconsider.

o-t-w avatar Mar 07 '19 11:03 o-t-w

For me it is very unreadable. Also you need add new newlines before add new property, It is very uncomfortable. Also some properties can have very long values and it will be inconsistently:

.static { position: static; }
.bg { background: very very very very very very very very very very very very very very very very many and long values; }

To

.static { position: static; }
.bg { 
  background: very very very very very very very very very very very very very very very very many and long values; 
}

alexander-akait avatar Mar 07 '19 11:03 alexander-akait

I agree with @o-t-w, there is cases when we don't want three lines for small declarations.

@evilebottnawi's point is a bit less relevant, for very very very very very very very very very very very many and long values, there is always line breaks and comas. It's not the point here.

Stylelint rule declaration-block-single-line-max-declarations offers a way to fine tune this behaviour, why Prettier don't ? I don't say that it has to be a default option to Prettier to support this behaviour, but it would be welcomed having a way to fit to our Stylelint configuration.

Please be open minded.

Yago avatar Mar 08 '19 09:03 Yago

Stylelint rule declaration-block-single-line-max-declarations offers a way to fine tune this behaviour, why Prettier don't ?

Because Prettier is an opinionated code formatter.

Please be open minded.

The issue is open :)

lydell avatar Mar 08 '19 09:03 lydell

"Because Prettier is an opinionated code formatter." I understand and I think this is a good thing in general. You certainly don't need to offer all the configuration options of a linter, but this is one that makes Prettier unusable for me :(

o-t-w avatar Mar 21 '19 16:03 o-t-w

@o-t-w

this is one that makes Prettier unusable for me

How? It is break your code? It is just spaces/newlines

alexander-akait avatar Mar 21 '19 16:03 alexander-akait

@evilebottnawi Well if I didn't care how code looked I'd leave it as an unformatted mess rather than using Prettier in the first place.

What I mean is that I dislike this formatting so much that I would rather go through the pain and tedium of manually formatting all my CSS rather than using Prettier 😖. Please don't make me do that!

What is the benefit of not making this configurable?

o-t-w avatar Mar 21 '19 16:03 o-t-w

@o-t-w

Well if I didn't care how code looked I'd leave it as an unformatted mess rather than using Prettier at all.

It is formatted well, just leave formatting for prettier, it is readable and looks good and i don't think we should change behavior.

What is the benefit of not making this configurable?

https://prettier.io/docs/en/option-philosophy.html

alexander-akait avatar Mar 21 '19 16:03 alexander-akait

On that matter, it seems clear that Prettier (or the team behind it) offers an opinion and if we don't agree, we don't use it at all for CSS. Period.

I personally agree with almost everything with the Prettier's JavaScript opinions, I use and love it for that! But for CSS, those opinions are not compliant with the stylelint-config-standard and the default value of 1 for the declaration-block-single-line-max-declarations. In my opinion, it's a much more readable, cleaner and lighter practice.

In the end, I understand that Prettier is opinionated by nature, but I think opinions are made to be discussed, not to be imposed by a small group of maintainers (even if their work is amazing, it's not the matter here, keep going), that's the beauty of open-source. Maybe a solution is to hold a vote for that kind of best practice to see what is the community's opinion. 🤔 I agree that options are maybe not the solution for Prettier, but the opinions have to represent the majority.

Thanks for allowing this discussion 😄 (it's maybe a wider matter than “simply” single line property formatting in CSS)

Yago avatar Mar 22 '19 14:03 Yago

Okey, we need investigate all popular styleguides, if somebody has time feel free to do it and put information here, personally i don't worries about spaces and newlines (within a reasonable), so we can revisit our output

alexander-akait avatar Mar 22 '19 15:03 alexander-akait

Using both single-line declaration blocks and multi-line declaration blocks within the same stylesheet is fairly common practice no?

Typically if the declaration block only contains a single declaration, I might prefer to keep it on a single line. Apart from saving space, the real advantage is that it can help readability of declarations that follow a repeating/similar pattern.

Example Input:

a { text-decoration: none; }

ul,
ol {
  list-style: none;
  padding: 0;
}

@keyframes rainbow {
  0% { color: #ff0000 };
  16% { color: #ff9b00 };
  33% { color: #ffff00 };
  50% { color: #9bff00 };
  66% { color: #0000ff };
  83% { color: #9b00ff };
  100% { color: #ff00ff };
}

Output:

a {
  text-decoration: none;
}

ul,
ol {
  list-style: none;
  padding: 0;
}

@keyframes rainbow {
  0% {
    color: #ff0000;
  }
  16% {
    color: #ff9b00;
  }
  33% {
    color: #ffff00;
  }
  50% {
    color: #9bff00;
  }
  66% {
    color: #0000ff;
  }
  83% {
    color: #9b00ff;
  }
  100% {
    color: #ff00ff;
  }
}

I don't think this is something that should be made configurable either, but I wonder if others think there is a place for single-line CSS declaration blocks in Prettier.

Isn't this somewhat similar in nature to #4765?

davidjaldred avatar Apr 29 '19 18:04 davidjaldred

This is beneficial means of CSS(like) beautification. As a proof of concept try the compressed-css option of Pretty Diff to play around with a vaguely similar idea. This option has proven wildly popular with my users and would benefit Prettier users as well.

prettydiff avatar May 13 '19 15:05 prettydiff

Prettier allows JS oneliners like:

var debug = ({ message, stack }) => console.error({ message, stack });
configure({ port: process.env.PORT }).catch(debug);

Overall, condensing micro statements helps maintain code. Lets me see all necessary logic on one screen, keeping multiple terminals open. Allowing the same for CSS would be nice.

nykula avatar Jul 13 '19 13:07 nykula

Anyway you can use stylelint-prettier and setup stylelint rules to fit this in one line, it is not hard

alexander-akait avatar Jul 13 '19 13:07 alexander-akait

Prettier is much lighter, and the point is to be internally consistent and not customize. I've been setting up stylelint, but every project using Prettier can benefit from the single line CSS rule. Will try to implement once I'm done with my current backlog.

nykula avatar Jul 13 '19 17:07 nykula

What about this case:

.mt7, 
.mt-standard {
  margin-top: 16rem;
}

or

.mt7, .mt-standard { margin-top: 16rem; }

alexander-akait avatar Aug 28 '19 15:08 alexander-akait

@evilebottnawi Selectors do belong each on own line IMO:

.mt7,
.mt-standard { margin-top: 16rem; }

nykula avatar Aug 28 '19 16:08 nykula

Not sure it is good idea, it can potential hard to read

alexander-akait avatar Aug 28 '19 17:08 alexander-akait

Yep is there a way to fix this? Example: You want to reset your CSS

Before:

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
}

After

html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
  margin: 0;
  padding: 0;
  border: 0;
}

FrederickEngelhardt avatar Sep 13 '19 21:09 FrederickEngelhardt

+1 here, I develop website since 15 years, single line CSS formatting, in the era of ultra wide screen is far far more quick and easier that the 1 property per line formatting. Still don't understand how we can work with 3 visible selector (barely more) on a single screen.

PubliAlex avatar Oct 28 '19 14:10 PubliAlex

I've just installed Prettier in vscode-insders to format some CSS code we have. The first thing I stumble upon, besides the great other things it does, is this:

Original:

/* prettier-ignore-start */
.item1 {grid-area: header;}
.item2 {grid-area: menu;}
.item3 {grid-area: main;}
.item4 {grid-area: right;}
.item5 {grid-area: footer;}
/* prettier-ignore-end */

After formatting:

/* prettier-ignore-start */
.item1 {
  grid-area: header;
}
.item2 {
  grid-area: menu;
}
.item3 {
  grid-area: main;
}
.item4 {
  grid-area: right;
}
.item5 {
  grid-area: footer;
}
/* prettier-ignore-end */

I really hoped using the /* prettier-ignore-start */ and /* prettier-ignore-end */ would've fixed this for me and kept things on one line as they were. But no luck...

DarkLite1 avatar Jan 29 '20 09:01 DarkLite1

I would give anything to have the option to allow for a single line css declaration. 😄

richardtaylordawson avatar Feb 05 '20 00:02 richardtaylordawson

How about format it like object in js. If it's original in single-line and can fit, format in single-line. Otherwise multi-lines.

fisker avatar Mar 24 '20 02:03 fisker

I would love to write a PR that changed it so that Prettier did Fisker's formatting. Let me know if there is interest?

robert-j-webb avatar Jun 20 '20 18:06 robert-j-webb

That’s against the point of Prettier though. Preserving input slowly undermines what Prettier tries to do. Taken to the extreme, Prettier would just pass your code through unmodified.

I feel there are two camps of people here: Those who always want multiline rules, and those who sometimes want single-line ones. I think it’s great that Prettier takes a decision here, so that teams won’t argue over if a rule should be single or multi line.

lydell avatar Jun 21 '20 18:06 lydell

The same behaviour as Prettier implements for objects in JS seems like the best approach -- and Prettier users are already familiar with this behaviour in that context (by definition), so it oughtn't to be controversial.

simonwiles avatar Jun 21 '20 23:06 simonwiles

Yes, we use something like that for JS objects but we don’t want more of it.

lydell avatar Jun 22 '20 07:06 lydell

That’s against the point of Prettier though. Preserving input slowly undermines what Prettier tries to do. Taken to the extreme, Prettier would just pass your code through unmodified.

I feel there are two camps of people here: Those who always want multiline rules, and those who sometimes want single-line ones. I think it’s great that Prettier takes a decision here, so that teams won’t argue over if a rule should be single or multi line.

You make a valid point here. Taken away the question avoids the discussion all together and forces everyone to use the same style.

An other way might be just adding the option to fit all code on one line whenever that's possible and have teams decide if they want to allow this in the config file. If they do, then the one liners philosophy will be applied for all files and not selectively for this line and not for another. Meaning, it's also consistent for everyone.

Food for thought....

DarkLite1 avatar Jun 22 '20 07:06 DarkLite1

The same behaviour as Prettier implements for objects in JS seems like the best approach -- and Prettier users are already familiar with this behaviour in that context (by definition), so it oughtn't to be controversial.

One could even argue that not introducing the same behavior for CSS as is used for JS is just introducing more inconsistency.

samuelfarrell avatar Jun 22 '20 16:06 samuelfarrell

I still think that collapsing is a very bad idea. It is not only unreadable in most cases and is difficult for the eye to perceive. But it also adds new problems:

  • should we add ; (semicolon)? somebody will say yes, somebody will say no
  • prettier uses print width to collapse something in one line, so .foo { color: red; display: block; } should be collapsed in the one line, but most of style guides (where one line syntax is used), recommend do it only for a one property. Again problems between developers what is better.
  • there are cases when we output complex CSS selectors in favor of readability, instead if print width
  • it is not popular style, so respect default user input is not the good idea for most of developers (based on my work in stylelint, maybe I am wrong, feel free to show it)
  • some developers uses mixed style, let's look on bootstrap - https://github.com/twbs/bootstrap/blob/main/scss/_reboot.scss
  • and we don't want new options, sorry

alexander-akait avatar Jun 22 '20 16:06 alexander-akait

I recently formatted my entire companies Sass codebase, and I have to say, this is not an uncommon pattern. And when it shows up, it really makes it pretty ugly.

There's the architecture decision of atomic classes in CSS, where each class is one property, so this rule really affects these files.

Also, Maps are also affected by this rule, which is directly correlated to JavaScript Objects/Arrays, ie: #8553 :

// Formatted:
sass-map: (
  another-map: (
    1px,
    2px,
    3px,
  ),
)

In JS, this is what that looks like

let a = {
  arr: [
    "1px",
    "2px",
    "3px",
 ]
}

Becomes

let a = {
  arr: ["1px", "2px", "3px"],
};

However, prettier for JS is also flexible, in that it allows single line properties, but it also allows to use new lines to break properties out into new lines playground

In essence, we could have formatting that would accept both as valid (without an option):

.foo { color : red; font-size: 16px; }

.foo {
	color : red;
	font-size: 16px;
}

robert-j-webb avatar Jun 22 '20 18:06 robert-j-webb