lightningcss icon indicating copy to clipboard operation
lightningcss copied to clipboard

Merging adjacent rules with *almost* the same declarations

Open heypiotr opened this issue 2 years ago • 3 comments

README says:

Merging adjacent rules with the same selectors or declarations when it is safe to do so.

This works as advertised:

.foo {
    background-color: red;
}
.bar {
    background-color: red;
}

/* output */
.foo,.bar{background-color:red}

But I wonder, is there any reason not to merge partially-indentical rules?

.foo {
    background-color: red;
    padding: 20px;
}
.bar {
    background-color: red;
    padding: 40px;
}

/* actual output */
.foo{background-color:red;padding:20px}.bar{background-color:red;padding:40px}

/* better output? */
.foo,.bar{background-color:red}.foo{padding:20px}.bar{padding:40px}

/* or maybe even: */
.foo,.bar{background-color:red;padding:20px}.bar{padding:40px}

Or am I wrong to think that as long as the rules are adjacent, this should be safe to do?

(The gains aren't big in this simplified example, but we have CSS with long adjacent rules that differ in only one or two declarations, and it quickly adds up.)

heypiotr avatar Sep 06 '22 14:09 heypiotr

Note that in some cases, depending on the selector length, this may actually make the output larger. For example:

.somelongselectorname{background-color:red;padding:20px}.someotherlongselectorname{background-color:red;padding:40px}

.somelongselectorname,.someotherlongselectorname{background-color:red;padding:20px}.someotherlongselectorname{padding:40px}

devongovett avatar Sep 06 '22 17:09 devongovett

Yeah, that's fair. Out of curiosity I checked what csso does, and it seems to be using whichever ends up shorter.

Just to add a practical example to this conversation, what we're dealing with is more like:

/* optimal? output */
.framer-iekIZ .framer-1kq0lbv,
.framer-iekIZ .framer-1x8f0vg,
.framer-iekIZ .framer-cbkbdb {
  align-content: center;
  align-items: center;
  display: flex;
  flex: none;
  flex-direction: column;
  flex-wrap: nowrap;
  height: min-content;
  justify-content: flex-start;
  overflow: hidden;
  position: relative;
  width: 100%;
}
.framer-iekIZ .framer-1kq0lbv {
  background-color: #fff;
  gap: 70px;
  padding: 100px 0 0;
}
.framer-iekIZ .framer-1x8f0vg {
  background-color: var(--token-26e3cb56-8447-4a64-9b7d-37f16a9909d4, #ffffff);
  gap: 80px;
  padding: 100px 50px 60px;
}
.framer-iekIZ .framer-cbkbdb {
  gap: 0;
  padding: 0;
}

Without merging the rules like that, we end up with the first chunk of declarations repeated 3 times.

heypiotr avatar Sep 07 '22 07:09 heypiotr

Hey @devongovett, friendly bump for this one here. While taking a look into LightningCSS, I've compared it to csso and this seemed to be the reason why the output of lightningcss is slightly larger compared to csso.

kurtextrem avatar Feb 28 '24 11:02 kurtextrem