# Performance and Accessibility Guide This section will help new contributors to get an overview of the accessbility and performance guidelines laid out to ensure maintainability of the codebase. Please have a look at this guide before opening pull requests to ensure that your changes promote accessibility and performance. ## Performance This section covers new changes and practices introduced in the codebase to support performance. ### Linking script or stylesheets On linking scripts or stylesheets to html pages, make sure that you use the rails helper function `javascript_include_tag` and `stylesheet_include_tag`. Before ading scripts/stylesheets, follow these guidelines:- - If files are already a part of application.js, there is no need to include them as separate links. - If files are part of the file assets.rb, then inorder to include them the path should be the same as the one in assets.rb. For example `<%= stylesheet_link_tag "/lib/leaflet/dist/leaflet.css" %>` should be `<%= stylesheet_link_tag "leaflet/dist/leaflet.css" %>` - If files are already present as yarn packages, import it from `/lib` instead of adding cdn links. ### Lazyloading of Images Lazyloading of images has been introduced [refer https://github.com/publiclab/plots2/pull/8043] using lazyload-rails gem. To lazyload an image, follow the following steps- - First make sure that the image is using the `image_tag` rails helper instead of an `img` tag [refer https://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html]. - Now, you can add `class:lazy` to this image. - Add the following inline script to the html page. `<script> $(function(){ $("img").lazyload(); }); </script>` ### Loading Critical css and rest asynchronously This change only loads critical css (css applicable for the page) on page load and the rest is loaded asynchronously. You can refer https://github.com/publiclab/plots2/pull/7996 for the changes made. This is accomplished with the help of gems `loadcss-rails` and `critical-path-css-rails` and is only carried out for `application.css` file. ### Font-awesome-rails gem for icons The font awesome library is now pulled from the `font-awesome-rails` gem [refer this pr https://github.com/publiclab/plots2/pull/7938]. This gem support Font Awesome version 4.7. Since some icons used by Leaflet Environmental Layers make use of FA version 5, hence an additional Font Awesome v5 has also been linked through cdn in file `layouts/application.html.erb`. Hence it is possible to add FA v4.7 or v5 icons as per your convenience. For FA v5 icons, make sure not to use the prefix `fa` since it is used for FA v4.7. Instead stick to `fas/far/fab` as per your requirement. ### Async or defer tag for scripts If the scripts you are adding are independent of other scripts and not required immediately on page load, adding defer/async tag to them can help improve performance. - Defer tag to be used for scripts that need to be fetched asynchronously but executed after dom construction is over. Useful in situations when our script depends on other scripts for example jquery. - Async tag to be used for scripts that need to be fetched and executed asynchronously. Useful for situations where our script is independent of other scripts and other scripts also don't rely on our script for execution. ### Adding images of next-gen formats JPEG 2000, JPEG XR, and WebP are image formats that have superior compression and quality characteristics compared to their older JPEG and PNG counterparts. Uploading and using images in these formats rather than JPEG or PNG means that they will load faster and consume less cellular data. ### Use .size instead of .length/.count `.length` aims to fetch all the entries of the db till the length is reached and then calculates the count. This leads us to unnecessarily fetching all the records. ``` Book.all.length Book Load (1.3ms) SELECT "books".* FROM "books" => 100 books = Book.all Book Load (1.3ms) SELECT "books".* FROM "books" books.length => 100 ``` While `.count` only calculates the count but if the entries are already fetched then it still makes an extra query. ``` books = Book.all Book Load (1.3ms) SELECT "books".* FROM "books" books.count (0.2ms) SELECT COUNT(*) FROM "books" => 100 ``` So depending on whether our records have been fetched already we may decide which method to use over the other. The `.size` method is a method that determines which method between count and length to execute. If we have already loaded the entries, it will use `.length`. If we haven’t, it will use `.count`. Size can therefore be used in most cases to save you having to worry about any of the performance considerations. ### Using minified css/js The minification of js is achieved by incorporating the Uglifier gem. This allows minification of js files that are a part of the asset pipeline. When adding new javascript files that are not a part of the asset pipeline, but instead are a part of /lib it is recommended to add code in the production.rb file to minify these scripts. Here is an example of how this can be done:- ``` Uglifier.new(harmony: true).compile(File.read("public/lib/leaflet-environmental-layers/lib/glify.js"))` ``` We can then check if the file is getting minified or not by running to trigger compilation instead of fetching these scripts from the cache: `rake assets:precompile` And then subsequently running a Lighthouse plugin check on the given url to verify whether the script in question is included under the **Minify Javascript** section of suggestions flagged by Lighthouse. ### Lighthouse CI for further performance and accessibility maintainability ### ## Accessibility This section covers new changes and practices introduced in the codebase to support accessibility. ### Adding aria-labels for empty buttons When navigating to a button, descriptive text must be presented to screen reader users to indicate the function of the button. If your button contains only an icon/image and no text, then to make it more accessible add an aria-label describing the action of the button. Also make sure that the action of the button described is not generic text such as "Click here" but something more meaningful such as "Submit note". The sample code is as follows:- `<button aria-label="More settings" type="button" class="btn btn-outline-secondary dropdown-toggle" id="pt-dropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" style="border-color:#ccc;">` ### Adding aria-labels for empty links If a link contains no text, the function or purpose of the link will not be presented to the user. This can introduce confusion for keyboard and screen reader users. If your link contains only an icon/image and no text, then to make it more accessible add an aria-label describing the target of the link. The sample code is as follows:- `<a aria-label="Add tags" id="tags-open" class="btn btn-circle btn-circle-sm" style="float:left;"><i class="fa fa-plus" style="color:#808080;"></i></a>` ### Adding form labels for inputs If a text label for a form control is visible, use the <label> element to associate it with its respective form control. `<label>Title <input class="form-control input-lg" type="text" id="title-input"/> </label>` If there is no visible label, either provide an associated label by creating the label tag before and referencing the input element id in the 'for' attribute of the label. The sample code is as follows:- `<label for="title-input"></label> <input class="form-control input-lg" type="text" id="title-input"/> ` You may also add a descriptive title attribute to the form control, or reference the label(s) using aria-labelledby. `<input aria-label="Enter Note Title" class="form-control input-lg" type="text" id="title-input" />` Labels are not required for image, submit, reset, button, or hidden form controls. ### Avoiding suspicious link-text Links, which are often read out of context, should clearly describe the destination or function of the link. Ambiguous text, text that does not make sense out of context, and extraneous text (such as "click here") can cause confusion and should be avoided. Where appropriate, reword the link text so that it is more descriptive of its destination when read out of context. Remove any extraneous text (such as "click here"). ### Navigation through tabs Tabindex values of 1 or greater specify an explicit tab/navigation order for page elements. Because it modifies the default tab order, cause confusion, and result in decreased keyboard accessibility, it should be avoided. If the natural tab order is already logical, remove the tabindex. Otherwise, consider restructuring the page so that tabindex is not needed. If tabindex is maintained, ensure that the resulting navigation is logical and complete. ### Semantic structure of headings and text elements Headings provide document structure and facilitate keyboard navigation by users of assistive technology. These users may be confused or experience difficulty navigating when heading levels are skipped. For example - an `<h1>` is followed by an `<h3>`, with no intermediate `<h2>` Restructure the document headings to ensure that heading levels are not skipped. ### Adding alternative text for images Each image must have an alt attribute. Without alternative text, the content of an image will not be available to screen reader users or when the image is unavailable. Add an alt attribute to the image.If the content of the image is conveyed in the context or surroundings of the image, or if the image does not convey content or have a function, it should be given empty/null alternative text (alt="").The sample code is given as below:- ### Avoid underlined text Underlines almost universally indicates linked text. Consider removing the underline from the non-link text. Other styling (e.g., bold or italics) can be used to differentiate the text. Unless there is a distinct need for the underlined text, remove the underline from it.