Skip to content
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

Core Css class for visually invisible but screen-reader accessible elements #5542

Merged
merged 5 commits into from
Oct 13, 2016

Conversation

aghassemi
Copy link
Contributor

This PR introduced a new core Css class amp-screen-reader that can be used by us or page authors to visually hide elements but keep them accessible to screen-readers.

We use this new class in sidebar to fix #5517.

Also as part of this PR, we are now installing core styles in the testing iframe so that we can use computedStyles to ensure proper Css is being applied.

/cc @camelburrito @dvoytenko

* changing width from 1 to 0 would prevent TalkBack from activating (clicking)
* buttons despite TalkBack reading them just fine.
*/
.amp-screen-reader {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.-amp-screen-reader

We dont want to make this overridable

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we will be doing most of the a11y for things with interactions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although I don't want it to be overridable, I do want page authors to use it in their own markup to fix a11y issues in their page. For now renamed to -amp but this is something we should expose as part of the core kick-start Css.

* buttons despite TalkBack reading them just fine.
*/
.amp-screen-reader {
position: fixed !important;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if more of these elements would make fixed layer operations slow. May be we should just whitelist from fixed layer somehow.

CC @dvoytenko

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed elements in our runtime css are not added to fixed layer by default. This should never make it to fixed layer, not because of performance but because fixed layer breaks DOM hierarchy which breaks accessibility.

border: none !important;
margin: 0 !important;
padding: 0 !important;
display: block !important;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this matter? once you set positioning-absolute/static i think you dont have to set this

Copy link
Contributor Author

@aghassemi aghassemi Oct 12, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am setting display:block !important to ensure when this class is used in combination with other classes/styles on an element, the display is never set to none (which would defeat the purpose of this class all together). Will add some comments to the code to clarify.

* changing width from 1 to 0 would prevent TalkBack from activating (clicking)
* buttons despite TalkBack reading them just fine.
*/
.amp-screen-reader {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than doing this in the css i would create a method in dom.js that would add this div and this would make it explicit when being called from inside the extension's build callback.

@dvoytenko what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not always a div ( actually most cases it would be a button or a p) and it is not always a new element that is created in a component, sometimes we want to toggle this class on an existing node (for example to fix #5487 we could just add this to the next/previous buttons when hiding them).

We can add dom.js utilities but we should keep this in Css (another reason to keep it in Css is that we want to expose this to page authors as part of the kick-start core Css)

@aghassemi
Copy link
Contributor Author

@jridgewell Please review the test-amp-fx-flying-carpet.js changes. They broke because we now install the runtime Css when creating the test iframe and therefore iframe.doc.body.style.height = '400vh' was not being applied because of !important! rules coming from runtime Css.

@@ -44,7 +44,11 @@ describe('amp-fx-flying-carpet', () => {
iframe = i;
toggleExperiment(iframe.win, 'amp-fx-flying-carpet', true);

iframe.doc.body.style.height = '400vh';
const bodyResizer = iframe.doc.createElement('div');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

different way of sizing the body's height. We now install the runtime Css when creating the test iframe and therefore iframe.doc.body.style.height = '400vh' was not being applied because of !important! rules coming from runtime Css was overriding it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, ok.

@@ -99,7 +99,19 @@ export class AmpSidebar extends AMP.BaseElement {
this.close_();
}
});
//TODO (skrish, #2712) Add history support on back button.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't delete this todo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's done though...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whooops.

screenReaderCloseButton.addEventListener('click', () => {
this.close_();
});
this.element.appendChild(screenReaderCloseButton);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this element going to be removed eventually?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope, will always be there.

screenReaderCloseButton.textContent = 'Close the sidebar';
screenReaderCloseButton.classList.add('-amp-screen-reader');
// This is for screen-readers only, should not get a tab stop.
screenReaderCloseButton.tabIndex = -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to create a screenReaderElement function that does this stuff for you?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generic one doesn't make sense cause these elements could be buttons, paragraphs, links, etc.. depending on the use-case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yah, but we can pass the element to make. Essentially, if we always want .-amp-screen-reader and tabIndex = -1, it'd be helpful because we're gonna forget the tabIndex.

function createScreenReaderElement(tag) {
  const elem = doc.create(tag);
  // ... psuedocode...
  return elem;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I thought this was being added on open.

Copy link
Contributor Author

@aghassemi aghassemi Oct 12, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about

/**
 * Visually hides an element but keeps it accessible to screen readers.
 * If opt_visibleOnlyForScreenReaders is false or element was already only
 * visible to screen-readers, it removes the screen-reader specific styling
 * from the element.
 * @param {boolean=} opt_visibleOnlyForScreenReaders
 */
export function toggleScreenReaderVisibility(element, opt_visibleOnlyForScreenReaders) {
  if (opt_visibleOnlyForScreenReaders === undefined) {
    opt_visibleOnlyForScreenReaders = !(element.classList.contains('-amp-screen-reader'));
  }

  element.classList.toggle('-amp-screen-reader');
  //TODO have to check whether default is '' or null or undefined
  element.tabIndex = opt_visibleOnlyForScreenReaders ? -1 : '';
}

in style.js

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would need to hide hide these when they aren't visible. But I like the idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, I don't want this to be used to hide hide things. There are cases where you want to apply ''-amp-screen-reader" to an existing visible node and then remove ''-amp-screen-reader" later to make the node visible again for everyone. Let's do the refactoring later when we have more uses of this, I think refactoring this right now might be premature.

@aghassemi
Copy link
Contributor Author

@mkhatib @camelburrito @jridgewell PTAL, I like to merge this to unblock #5487 and #5503. Thanks!

@@ -121,11 +121,44 @@ i-amp-sizer {
}

.-amp-replaced-content {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔪

@aghassemi aghassemi merged commit 91eef43 into ampproject:master Oct 13, 2016
Lith pushed a commit to Lith/amphtml that referenced this pull request Dec 22, 2016
Lith pushed a commit to Lith/amphtml that referenced this pull request Dec 22, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[A11Y] Sidebar always needs an accessible (yet invisible) close button.
4 participants