-
Notifications
You must be signed in to change notification settings - Fork 327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix flash of unstyled content with conditional reveals #885
Conversation
src/components/radios/template.njk
Outdated
@@ -61,7 +61,7 @@ | |||
}) | indent(6) | trim }} | |||
</div> | |||
{% if item.conditional %} | |||
<div class="govuk-radios__conditional" id="{{ conditionalId }}"> | |||
<div class="govuk-radios__conditional{% if not item.checked %} is-hidden{% endif %}" id="{{ conditionalId }}"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For users that do not use macros, how do we document this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we handle toggling this in JS somehow? If we add .js-hidden
to all conditionals markup by default, no FOUC. When JS loads we check the preceeding .govuk-checkboxes__item
sibling. If the input inside of it is checked
, remove .js-hidden
from the conditional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I realised that this still wouldn't work because we need to we do .js-enabled .js-hidden
in CSS so that style doesn't kick in until JS has loaded 😞 I'll keep on thinking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's currently how the JavaScript logic works. The logic in the template is for the initial render.
I think this might not be a big issue since the example we use in the Design System website has a pre-checked input which means you'd see it in the generated HTML.
7a3f0e2
to
6e67929
Compare
@@ -139,7 +139,7 @@ | |||
padding-left: $conditional-padding-left; | |||
border-left: $conditional-border-width solid $govuk-border-colour; | |||
|
|||
&[aria-hidden="true"] { | |||
.js-enabled &.is-hidden { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a common utility class would make sense.
(On a separate note, I think we should probably prefix our JS classes. But let's discuss that another time, I don't want to derail this PR 😁 )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You thinking govuk-js-hidden
?
It's OK to raise things like this as a blocker since classes are part of our public API, so you're not derailing things.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I was thinking of govuk-js-hidden
. I was even thinking of js-hidden-govuk
as it's handy to recognise JS classes at a glance. But it just sounds too weird... 😅
But js-hidden
just seems like it would very easily conflict with something else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed - makes sense, looks like we already use js-hidden, so maybe raise an issue for us to think about it after all 😬
https://github.com/alphagov/govuk-frontend/search?q=js-hidden&unscoped_q=js-hidden
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to change the 'is-hidden' to 'js-hidden' to be consistent with tabs.
feb5ddd
to
4a3cb14
Compare
src/components/tabs/_tabs.scss
Outdated
} | ||
} | ||
|
||
} | ||
|
||
.js-hidden { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good news is the tests found this selector being defined globally
i imagine I should fix this behaviour in a different PR first...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes me think having this class used with slightly different behaviours is indeed dangerous.
So we should either
- Continue doing js-hidden for specific components but namespacing with their component names:
govuk-tabs-js-hidden
or.govuk-tabs .js-hidden
? - Pull
js-hidden
out into a utility class that is used by tabs and conditional reveals
I feel 2. is probably the best way, since others can use this class too.
js-hidden
is something from the old world too, so it'll always be a 'helper' that's defined globally in gov.uk template.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pushed up some scrappy working to see what that might look like, will do something clean next week.
b76f36d
to
4a3cb14
Compare
4a3cb14
to
08d21f7
Compare
Uses the presence of the `js-enabled` class to know when to hide or show content.
Uses the presence of the `js-enabled` class to know when to hide or show content.
08d21f7
to
745c008
Compare
@@ -40,7 +41,7 @@ Checkboxes.prototype.setAttributes = function ($input) { | |||
$input.setAttribute('aria-expanded', inputIsChecked) | |||
|
|||
var $content = document.querySelector('#' + $input.getAttribute('aria-controls')) | |||
$content.setAttribute('aria-hidden', !inputIsChecked) | |||
$content.classList.toggle('govuk-checkboxes__conditional--hidden', !inputIsChecked) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the case that CSS fails but JS succeeds, should we also include 'aria-hidden'? Or is this a bit too over the top?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reckon this is fine as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me 👏
@NickColley is there anything blocking this from being merged? |
@36degrees just wanted to get more eyes on it since it's a big change |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, though tests could be more focussed.
const $component = $('.govuk-checkboxes') | ||
|
||
const $firstConditional = $component.find('.govuk-checkboxes__conditional').first() | ||
expect($firstConditional.html()).toContain('Conditional content that should be hidden') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be good to split this out into its own test and just have the one assertion per test.
@@ -40,7 +41,7 @@ Checkboxes.prototype.setAttributes = function ($input) { | |||
$input.setAttribute('aria-expanded', inputIsChecked) | |||
|
|||
var $content = document.querySelector('#' + $input.getAttribute('aria-controls')) | |||
$content.setAttribute('aria-hidden', !inputIsChecked) | |||
$content.classList.toggle('govuk-checkboxes__conditional--hidden', !inputIsChecked) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reckon this is fine as is.
If the conditional reveal JavaScript is slow to execute it can result in showing the user their contents briefly which can be jarring.
See the original issue for an example: #787
Fixes #787
Tested in:
Assistive technologies:
I've tested this in VoiceOver and since
display: none
has the same behaviour asaria-hidden=true
(styled withdisplay: none
), I've decided not to do a full test of assistive technologies.Pages to review:
https://trello.com/c/o9krC0SR/1195-conditional-reveals-result-in-a-flash-of-unstyled-content-as-the-page-loads