Skip to content

Commit

Permalink
feat(star rating): add read-only state and enhance accessibility (#2184)
Browse files Browse the repository at this point in the history
* Star rating now has a read-only state
* Star rating has been slightly changed for accessibility purpose; a visually hidden `span` matching the title attribute was added and color contrast of inactive stars has been updated.
* The `form-star-rating()` mixin is now deprecated.

---------

Co-authored-by: MewenLeHo <mewen.leho.ext@orange.com>
Co-authored-by: Julien Déramond <julien.deramond@orange.com>
  • Loading branch information
3 people authored Sep 6, 2023
1 parent b3e811f commit 319b8df
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .bundlewatch.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
},
{
"path": "./dist/css/boosted.min.css",
"maxSize": "40.25 kB"
"maxSize": "40.5 kB"
},
{
"path": "./dist/js/boosted.bundle.js",
Expand Down
1 change: 0 additions & 1 deletion scss/_mixins.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
@import "mixins/lists";
@import "mixins/forms";
@import "mixins/table-variants";
@import "mixins/star-rating"; // Boosted mod

// Skins
@import "mixins/border-radius";
Expand Down
29 changes: 21 additions & 8 deletions scss/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1180,15 +1180,28 @@ $form-check-btn-check-disabled-opacity: null !default;
$form-check-inline-margin-end: 1rem !default;

// Boosted mod: Star rating
$form-star-size: 1.5625rem !default;
$form-star-size-sm: 1.25rem !default;
$form-star-margin-between: -.125rem !default;
$form-star-size: 1.5625rem !default;
$form-star-size-sm: 1.25rem !default;
$form-star-margin-between: -.125rem !default;

$form-star-rating-checked-color: $accessible-orange !default;
$form-star-rating-unchecked-color: $gray-700 !default;
$form-star-rating-hover-color: $black !default;

$form-star-rating-dark-checked-color: $primary !default;
$form-star-rating-dark-unchecked-color: $gray-500 !default;
$form-star-rating-dark-hover-color: $white !default;

$form-star-rating-checked-icon: escape-svg(url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 25 25'><path fill='#000' stroke='#000' d='m12.5 4.523 2.016 6.227 6.542-.005-5.296 3.843 2.027 6.224L12.5 16.96l-5.289 3.852 2.027-6.224-5.296-3.843 6.542.005L12.5 4.523Z'/></svg>")) !default;
$form-star-rating-unchecked-icon: escape-svg(url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 25 25'><path fill='transparent' stroke='#000' d='m12.5 4.523 2.016 6.227 6.542-.005-5.296 3.843 2.027 6.224L12.5 16.96l-5.289 3.852 2.027-6.224-5.296-3.843 6.542.005L12.5 4.523Z'/></svg>")) !default;
$form-star-rating-sm-checked-icon: escape-svg(url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='#000' stroke='#000' d='M10 3.943 11.54 8.7l4.998-.004-4.046 2.936 1.548 4.755L10 13.444l-4.04 2.943 1.548-4.755-4.046-2.936L8.46 8.7 10 3.943Z'/></svg>")) !default;
$form-star-rating-sm-unchecked-icon: escape-svg(url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='transparent' stroke='#000' d='M10 3.943 11.54 8.7l4.998-.004-4.046 2.936 1.548 4.755L10 13.444l-4.04 2.943 1.548-4.755-4.046-2.936L8.46 8.7 10 3.943Z'/></svg>")) !default;
//fusv-disable
$form-star-focus-color: $black !default; // Deprecated in v5.2.3
$form-star-focus-outline: var(--#{$prefix}border-width) solid $form-star-focus-color !default; // Deprecated in v5.2.3
$form-star-focus-color-dark: $white !default; // Deprecated in v5.2.3
$form-star-focus-outline-dark: var(--#{$prefix}border-width) solid $form-star-focus-color-dark !default; // Deprecated in v5.2.3
$form-star-focus-box-shadow: $input-btn-focus-box-shadow !default; // Deprecated in v5.2.3
$form-star-focus-color: $black !default; // Deprecated in v5.2.3
$form-star-focus-outline: var(--#{$prefix}border-width) solid $form-star-focus-color !default; // Deprecated in v5.2.3
$form-star-focus-color-dark: $white !default; // Deprecated in v5.2.3
$form-star-focus-outline-dark: var(--#{$prefix}border-width) solid $form-star-focus-color-dark !default; // Deprecated in v5.2.3
$form-star-focus-box-shadow: $input-btn-focus-box-shadow !default; // Deprecated in v5.2.3
//fusv-enable

// End mod
Expand Down
84 changes: 45 additions & 39 deletions scss/forms/_star-rating.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,52 @@
//

.star-rating {
&.disabled,
--#{$prefix}star-rating-checked-color: #{$form-star-rating-checked-color};
--#{$prefix}star-rating-unchecked-color: #{$form-star-rating-unchecked-color};
--#{$prefix}star-rating-hover-color: #{$form-star-rating-hover-color};
--#{$prefix}star-rating-checked-icon: #{$form-star-rating-checked-icon};
--#{$prefix}star-rating-unchecked-icon: #{$form-star-rating-unchecked-icon};
font-size: $form-star-size;

&:disabled {
pointer-events: none;
--#{$prefix}star-rating-checked-color: var(--#{$prefix}border-color-translucent);
--#{$prefix}star-rating-unchecked-color: var(--#{$prefix}border-color-translucent);
}

> label {
display: block;
cursor: pointer;
}

> label,
span {
float: left;
width: 1em;
height: 1em;
font-size: $form-star-size;
cursor: pointer;
@include form-star-rating($accessible-orange);

&::before {
display: block;
width: 100%;
height: 100%;
mask-image: var(--#{$prefix}star-rating-checked-icon);
content: "";
background-color: var(--#{$prefix}star-rating-checked-color);
}

&:not(:first-of-type){
margin-left: $form-star-margin-between;
}
}

> input:checked ~ label {
@include form-star-rating($gray-500);
> input:checked ~ label::before,
.checked ~ span::before {
mask-image: var(--#{$prefix}star-rating-unchecked-icon);
background-color: var(--#{$prefix}star-rating-unchecked-color);
}

> input:checked + label {
@include form-star-rating($accessible-orange);
> input:checked + label::before {
mask-image: var(--#{$prefix}star-rating-checked-icon);
background-color: var(--#{$prefix}star-rating-checked-color);
}

> [data-focus-visible-added]:focus + label {
Expand All @@ -36,45 +57,30 @@
box-shadow: inset 0 0 0 add(1px, $focus-visible-inner-width) var(--#{$prefix}focus-visible-inner-color);
}

&:hover input + label {
@include form-star-rating($black);
&:hover input + label::before {
mask-image: var(--#{$prefix}star-rating-checked-icon);
background-color: var(--#{$prefix}star-rating-hover-color);
}

> input:hover ~ label {
@include form-star-rating($gray-500);
> input:hover ~ label::before {
mask-image: var(--#{$prefix}star-rating-unchecked-icon);
background-color: var(--#{$prefix}star-rating-unchecked-color);
}

> input:hover + label {
@include form-star-rating($black);
> input:hover + label::before {
mask-image: var(--#{$prefix}star-rating-checked-icon);
background-color: var(--#{$prefix}star-rating-hover-color);
}
}

.star-rating-dark {
> label {
@include form-star-rating($brand-orange);
}

> input:checked ~ label {
@include form-star-rating($gray-700);
}

> input:checked + label {
@include form-star-rating($brand-orange);
}

&:hover input + label {
@include form-star-rating($white);
}

> input:hover ~ label {
@include form-star-rating($gray-700);
}

> input:hover + label {
@include form-star-rating($white);
}
--#{$prefix}star-rating-checked-color: #{$form-star-rating-dark-checked-color};
--#{$prefix}star-rating-unchecked-color: #{$form-star-rating-dark-unchecked-color};
--#{$prefix}star-rating-hover-color: #{$form-star-rating-dark-hover-color};
}

.star-rating-sm > label {
.star-rating-sm {
--#{$prefix}star-rating-checked-icon: #{$form-star-rating-sm-checked-icon};
--#{$prefix}star-rating-unchecked-icon: #{$form-star-rating-sm-unchecked-icon};
font-size: $form-star-size-sm;
}
2 changes: 2 additions & 0 deletions scss/mixins/_star-rating.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@include deprecate("`form-star-rating()`", "v5.3.2", "v6.0.0");

// scss-docs-start form-star-rating-mixin
@mixin form-star-rating($color) {
background-image: escape-svg(url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 25 25'><path fill='#{$color}' d='m12.5 2.9 2.379 7.35 7.721-.007-6.25 4.536 2.392 7.346-6.242-4.547-6.242 4.547 2.392-7.346-6.25-4.536 7.721.007Z'/></svg>"));
Expand Down
80 changes: 52 additions & 28 deletions site/content/docs/5.3/forms/checks-radios.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,19 +368,19 @@ Star rating system is built on top of radios. Simply add `.star-rating` to a `<f
<legend class="visually-hidden">Results relevance</legend>

<input type="radio" id="terrible" name="rating" value="1" class="visually-hidden">
<label for="terrible" title="Terrible"></label>
<label for="terrible" title="Terrible"><span class="visually-hidden">Terrible</span></label>

<input type="radio" id="bad" name="rating" value="2" class="visually-hidden">
<label for="bad" title="Bad"></label>
<label for="bad" title="Bad"><span class="visually-hidden">Bad</span></label>

<input type="radio" id="mixed" name="rating" value="3" class="visually-hidden">
<label for="mixed" title="Mixed"></label>
<label for="mixed" title="Mixed"><span class="visually-hidden">Mixed</span></label>

<input type="radio" id="good" name="rating" value="4" class="visually-hidden" checked>
<label for="good" title="Good"></label>
<label for="good" title="Good"><span class="visually-hidden">Good</span></label>

<input type="radio" id="excellent" name="rating" value="5" class="visually-hidden">
<label for="excellent" title="Excellent"></label>
<label for="excellent" title="Excellent"><span class="visually-hidden">Excellent</span></label>
</fieldset>
</form>
{{< /example >}}
Expand All @@ -395,19 +395,19 @@ Star ratings come with a smaller variant: `.star-rating-sm`.
<legend class="visually-hidden">Results relevance</legend>

<input type="radio" id="terrible2" name="rating" value="1" class="visually-hidden">
<label for="terrible2" title="Terrible"></label>
<label for="terrible2" title="Terrible"><span class="visually-hidden">Terrible</span></label>

<input type="radio" id="bad2" name="rating" value="2" class="visually-hidden">
<label for="bad2" title="Bad"></label>
<label for="bad2" title="Bad"><span class="visually-hidden">Bad</span></label>

<input type="radio" id="mixed2" name="rating" value="3" class="visually-hidden">
<label for="mixed2" title="Mixed"></label>
<label for="mixed2" title="Mixed"><span class="visually-hidden">Mixed</span></label>

<input type="radio" id="good2" name="rating" value="4" class="visually-hidden" checked>
<label for="good2" title="Good"></label>
<label for="good2" title="Good"><span class="visually-hidden">Good</span></label>

<input type="radio" id="excellent2" name="rating" value="5" class="visually-hidden">
<label for="excellent2" title="Excellent"></label>
<label for="excellent2" title="Excellent"><span class="visually-hidden">Excellent</span></label>
</fieldset>
</form>
{{< /example >}}
Expand All @@ -422,45 +422,67 @@ Add `.star-rating-dark` to the `.star-rating` for a dark variant.
<legend class="visually-hidden">Results relevance</legend>

<input type="radio" id="terrible3" name="rating" value="1" class="visually-hidden">
<label for="terrible3" title="Terrible"></label>
<label for="terrible3" title="Terrible"><span class="visually-hidden">Terrible</span></label>

<input type="radio" id="bad3" name="rating" value="2" class="visually-hidden">
<label for="bad3" title="Bad"></label>
<label for="bad3" title="Bad"><span class="visually-hidden">Bad</span></label>

<input type="radio" id="mixed3" name="rating" value="3" class="visually-hidden">
<label for="mixed3" title="Mixed"></label>
<label for="mixed3" title="Mixed"><span class="visually-hidden">Mixed</span></label>

<input type="radio" id="good3" name="rating" value="4" class="visually-hidden" checked>
<label for="good3" title="Good"></label>
<label for="good3" title="Good"><span class="visually-hidden">Good</span></label>

<input type="radio" id="excellent3" name="rating" value="5" class="visually-hidden">
<label for="excellent3" title="Excellent"></label>
<label for="excellent3" title="Excellent"><span class="visually-hidden">Excellent</span></label>
</fieldset>
</form>
{{< /example >}}

### Readonly

Make star ratings readable but non-editable by using `<span>`s instead of `<input>` elements.

{{< example >}}
<div class="star-rating">
<p class="visually-hidden">Star rating: rated 3 out of 5</p>

<div aria-hidden="true">
<span></span>
<span></span>
<span class="checked"></span>
<span></span>
<span></span>
</div>
</div>
{{< /example >}}

### Disabled

Make star ratings look inactive inside or outside a form by adding the `disabled` boolean attribute to the `<fieldset>` element and the `checked` boolean attribute to any `<input>` element.

{{< example >}}
<fieldset class="star-rating" disabled>
<input type="radio" id="terrible4" name="rating" value="1" class="visually-hidden">
<label for="terrible4" title="Terrible"></label>
<form>
<fieldset class="star-rating" disabled aria-hidden="true">
<legend class="visually-hidden">Disabled star rating</legend>

<input type="radio" id="terrible4" name="rating" value="1" class="visually-hidden">
<label for="terrible4" title="Terrible"><span class="visually-hidden">Terrible</span></label>

<input type="radio" id="bad4" name="rating" value="2" class="visually-hidden">
<label for="bad4" title="Bad"></label>
<input type="radio" id="bad4" name="rating" value="2" class="visually-hidden">
<label for="bad4" title="Bad"><span class="visually-hidden">Bad</span></label>

<input type="radio" id="mixed4" name="rating" value="3" class="visually-hidden" checked>
<label for="mixed4" title="Mixed"></label>
<input type="radio" id="mixed4" name="rating" value="3" class="visually-hidden" checked>
<label for="mixed4" title="Mixed"><span class="visually-hidden">Mixed</span></label>

<input type="radio" id="good4" name="rating" value="4" class="visually-hidden">
<label for="good4" title="Good"></label>
<input type="radio" id="good4" name="rating" value="4" class="visually-hidden">
<label for="good4" title="Good"><span class="visually-hidden">Good</span></label>

<input type="radio" id="excellent4" name="rating" value="5" class="visually-hidden">
<label for="excellent4" title="Excellent"></label>
</fieldset>
<span class="visually-hidden">rated 3 stars out of 5</span>
<input type="radio" id="excellent4" name="rating" value="5" class="visually-hidden">
<label for="excellent4" title="Excellent"><span class="visually-hidden">Excellent</span></label>
</fieldset>
<p class="visually-hidden">Disabled star rating: rated 3 out of 5</p>
</form>
{{< /example >}}

<!-- End mod -->
Expand All @@ -479,4 +501,6 @@ Variables for switches:

### Sass mixins

{{< deprecated-in "5.3.2" >}}

{{< scss-docs name="form-star-rating-mixin" file="scss/mixins/_star-rating.scss" >}}
20 changes: 20 additions & 0 deletions site/content/docs/5.3/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ If you need more details about the changes, please refer to the [v5.3.2 release]
- <span class="badge bg-success">New</span> In order to improve accessibility for people suffering from any form of color blindness, we added a visual cue to form elements on error when focused so information does not rely exclusively on color anymore. Although is has no direct impact, you might want to apply this same modification within your custom form controls if you have any.
- <span class="badge bg-success">New</span> Labels related to mandatory form fields have been improved for better accessibility. A `<span class="visually-hidden"> (required)</span>` element has been added to ensure correct restitution by assistive technologies like screen readers. Please reflect these modifications into your websites.

- <span class="badge bg-success">New</span> Star rating now has a `readonly` state.

- <span class="badge bg-warning">Warning</span> Star rating has been slightly changed for accessibility purpose; a visually hidden `span` matching the title attribute was added and color contrast of inactive stars has been updated. Please reflect this modification into your websites.

```diff
- <label for="excellent" title="Excellent"></label>
+ <label for="excellent" title="Excellent"><span class="visually-hidden">Excellent</span></label>
```
- <span class="badge bg-warning">Deprecated</span> The `form-star-rating()` mixin is now deprecated. We now use a `mask-image` CSS property to display the stars in this form element.

### CSS and Sass variables

- <details class="mb-2">
Expand All @@ -59,6 +69,16 @@ If you need more details about the changes, please refer to the [v5.3.2 release]
<li><code>$accordion-dark-button-hover-bg</code></li>
<li><code>$footer-accordion-active-color</code></li>
<li><code>$footer-accordion-btn-hover-bg</code></li>
<li><code>$form-star-rating-checked-color</code></li>
<li><code>$form-star-rating-checked-icon</code></li>
<li><code>$form-star-rating-dark-checked-color</code></li>
<li><code>$form-star-rating-dark-hover-color</code></li>
<li><code>$form-star-rating-dark-unchecked-color</code></li>
<li><code>$form-star-rating-hover-color</code></li>
<li><code>$form-star-rating-sm-checked-icon</code></li>
<li><code>$form-star-rating-sm-unchecked-icon</code></li>
<li><code>$form-star-rating-unchecked-color</code></li>
<li><code>$form-star-rating-unchecked-icon</code></li>
<li><code>$local-nav-active-bg</code></li>
<li><code>$local-nav-active-color</code></li>
<li><code>$local-nav-active-marker-width</code></li>
Expand Down

0 comments on commit 319b8df

Please sign in to comment.