react-rating icon indicating copy to clipboard operation
react-rating copied to clipboard

Feature request: Lighter DOM Size

Open rpastorelle opened this issue 4 years ago • 1 comments

I'm using a pretty simple SVG with 1 path for fullSymbol & emptySymbol, for example:

const StarFull = props =>
	<svg width="1em" height="1em" viewBox="0 0 19 19" {...props}>
		<path d="M3.844 18.458a.507.507 0 01-.302-.097.524.524 0 01-.206-.506l.983-5.76L.156 8.018a.51.51 0 01-.129-.53.517.517 0 01.415-.352l5.752-.841 2.573-5.239A.513.513 0 019.23.77a.52.52 0 01.463.287l2.572 5.239 5.756.841a.517.517 0 01.282.882l-4.162 4.077.982 5.76a.521.521 0 01-.205.506.509.509 0 01-.544.04l-5.148-2.718-5.15 2.718a.51.51 0 01-.233.057z" />
	</svg>;

const StarEmpty = (props) =>
	<svg width="1em" height="1em" viewBox="0 0 19 19" {...props}>
		<path d="M15.148 18.462a.494.494 0 01-.237-.061l-5.143-2.718L4.622 18.4a.509.509 0 01-.543-.04.521.521 0 01-.206-.506l.982-5.76-4.16-4.077a.51.51 0 01-.13-.53.517.517 0 01.415-.352l5.754-.841L9.31 1.056A.513.513 0 019.772.77a.52.52 0 01.463.287l2.571 5.239 5.754.84a.517.517 0 01.286.883l-4.16 4.077.98 5.76a.521.521 0 01-.518.607zM2.077 7.892l3.65 3.553c.123.118.18.293.151.46l-.863 5.018 4.514-2.37a.511.511 0 01.484 0l4.51 2.37-.863-5.018a.518.518 0 01.15-.46l3.652-3.554-5.043-.732a.51.51 0 01-.39-.285L9.772 2.308 7.514 6.874a.516.516 0 01-.39.285l-5.047.732z" />
	</svg>;

<Rating
  initialRating={3.5}
  emptySymbol={<StarEmpty />}
  fullSymbol={<StarFull />}
  fractions={2}
  readonly
/>

This RatingStars component outputs 45 nodes into the DOM 😮 Let's say you have a page of 30 items that each displayed a rating — the total DOM size is already 1,350 nodes without anything else on the page. You're page will get flagged every time by Lighthouse because it's going to exceed the recommended 1500 nodes.

Amazon uses image sprites but they get away with just 5 nodes per rating element.

rpastorelle avatar Jun 02 '21 18:06 rpastorelle

Hi @rpastorelle!

I see your point and it seems a fair concern.

This component aimed to be as the most flexible rating. But with flexibility probably comes less efficiency, or in our specific case, more elements/nodes 😄.

I am open to optimizations and I can spot some options, specially for read-only ratings. So I will keep this issue open just in case someone (or myself) had desire and time to contribute.

Now some insights and discoveries...

Rating structure

The rating symbols are composed by:

  • A parent span element that wraps the entire symbol. Used as a container of each symbol
  • Two children span elements that wrap the empty and the full symbols. Basically used to manage the visibility and the fraction of the symbol being shown
  • The variable number of elements of the empty and full elements

There are 3 extra wrapper elements for each symbol.

The formula to know the exact number of elements generated for a rating of n symbols would be something like this:

n symbols * (wrapper elements + number of elements emptySymbol + number of elements fullSymbol)

In your example:

5 * (3 + 2 + 2) = 35 (I don't know how you got 45 😅)

Amazon rating structure

I checked two types of star ratings, let's say the input and the read-only.

In the input rating each symbol is composed by two elements (a label and an input). So for a 5 star rating we have 10 elements.

<div class="a-section rating">
    <label name="star1" class="emptyStar" tabindex="1" aria-label="seleccionar para valorar vendedor con una estrella">
        <input name="star-rating" type="radio" value="1" class="radio-btn hide">
    </label>
    <label name="star2" class="emptyStar" tabindex="1" aria-label="seleccionar para valorar vendedor con dos estrellas">
        <input name="star-rating" type="radio" value="2" class="radio-btn hide">
    </label>
    <label name="star3" class="emptyStar" tabindex="1" aria-label="seleccionar para valorar vendedor con tres estrellas">
        <input name="star-rating" type="radio" value="3" class="radio-btn hide">
    </label>
    <label name="star4" class="emptyStar" tabindex="1" aria-label="seleccionar para valorar vendedor con cuatro estrellas">
        <input name="star-rating" type="radio" value="4" class="radio-btn hide">
    </label>
    <label name="star5" class="emptyStar" tabindex="1" aria-label="seleccionar para valorar vendedor con cinco estrellas">
        <input name="star-rating" type="radio" value="5" class="radio-btn hide">
    </label>
</div>

The read-only symbol is a pre-built image with the corresponding rating selected.

<i class="a-icon a-icon-star-small a-star-small-4-5 aok-align-bottom">
  <span class="a-icon-alt">4.7 out of 5 stars</span>
</i>

It uses the following sprite: image

As you can see in the image they have all ratings from 0 to 5 (with halves too 😉).

As a curiosity

I created a Lighthouse report on the same Amazon page I was looking into the read-only stars and here is what I got:

image

A code sandbox used for the investigation.

dreyescat avatar Jun 04 '21 16:06 dreyescat