In the world of web design, providing users with clear and intuitive feedback is essential for creating a positive user experience. HTML5 introduced two elements, <meter>
and <progress>
, that offer straightforward ways to display values and progress. These elements not only enhance the visual aspect of your web pages but also contribute to more accessible and meaningful interactions. This article will dive into the best practices for using these elements effectively, ensuring that your implementations are both functional and user-friendly.
Understanding <meter>
and <progress>
The <meter>
Element
The <meter>
element is designed to represent a value within a known range. It’s ideal for displaying measurements such as disk usage, score levels, or any scenario where a value is compared against a defined range.
For instance, it’s commonly used to show how much of a task is completed relative to the total.
Here’s a simple example of how the <meter>
element might be used:
<label for="diskUsage">Disk Usage:</label>
<meter id="diskUsage" min="0" max="100" value="70">70%</meter>
In this example, the <meter>
element shows that the disk usage is at 70% of its maximum capacity. The min
and max
attributes define the range, while the value
attribute indicates the current value.
The <progress>
Element
The <progress>
element, on the other hand, is used to show the progress of a task. It’s perfect for indicating how much of a process, like a file upload or a download, has been completed.
The <progress>
element provides a visual representation of progress, making it easy for users to gauge completion status at a glance.
Here’s an example of the <progress>
element:
<label for="fileUpload">File Upload Progress:</label>
<progress id="fileUpload" value="50" max="100">50%</progress>
In this case, the <progress>
element displays that the file upload is 50% complete, with value
representing the current progress and max
defining the total possible value.
Best Practices for Implementing <meter>
Use Appropriate Attributes
When implementing the <meter>
element, ensure that you use the min
, max
, and value
attributes correctly. The min
attribute sets the lower bound of the range, max
sets the upper bound, and value
represents the current measurement within this range.
For instance, if you’re displaying a battery level, you might use:
<label for="batteryLevel">Battery Level:</label>
<meter id="batteryLevel" min="0" max="100" value="40">40%</meter>
Provide Contextual Labels
Always provide labels for your <meter>
elements to ensure that users understand what the measurement represents. Use the label
element to associate the meter with a description.
This practice improves accessibility and clarity, making your data more meaningful to users.
<label for="diskUsage">Disk Usage:</label>
<meter id="diskUsage" min="0" max="100" value="60">60%</meter>
Ensure Accessibility
To enhance accessibility, make sure that the <meter>
element’s value is understandable to all users, including those using screen readers. Adding an accessible name and description helps screen readers convey the measurement’s context. For example:
<meter id="cpuUsage" min="0" max="100" value="80" aria-labelledby="cpuUsageLabel"></meter>
<span id="cpuUsageLabel" class="sr-only">CPU Usage: 80%</span>
In this example, the aria-labelledby
attribute links the meter to a label that provides a description for screen readers.
Best Practices for Implementing <progress>
Set Accurate Values
For the <progress>
element to be effective, ensure that the value
attribute accurately reflects the current state of progress and that the max
attribute represents the total amount needed to complete the task.
This accuracy ensures that users get a reliable representation of progress.
<progress id="uploadProgress" value="75" max="100">75%</progress>
Use Visual Cues and Feedback
To improve user experience, incorporate visual cues that indicate progress status. For example, consider changing the color or adding a percentage label to the <progress>
element to provide more detailed feedback.
This approach helps users easily understand their progress.
<progress id="uploadProgress" value="40" max="100" style="width: 100%; height: 20px;"></progress>
<span>Uploading: 40%</span>
Provide Alternative Text
In cases where the <progress>
element may not be fully understood by all users, include alternative text or descriptions to offer context. This additional information ensures that users with different needs can still comprehend the progress status.
<progress id="uploadProgress" value="40" max="100" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100">
40% complete
</progress>
The aria-valuenow
, aria-valuemin
, and aria-valuemax
attributes provide detailed information about the progress status for assistive technologies.
Common Challenges and Solutions
Dealing with Cross-Browser Compatibility
Different browsers may render <meter>
and <progress>
elements differently. To address cross-browser compatibility issues, test your implementations across multiple browsers and devices.
Use vendor prefixes or polyfills if necessary to ensure consistent behavior.
Handling Dynamic Updates
For applications that require real-time updates, such as live progress bars or dynamic measurements, ensure that the <meter>
and <progress>
elements are updated dynamically using JavaScript.
Use event listeners or AJAX to modify the value
attribute as needed.
function updateProgress(value) {
document.getElementById('uploadProgress').value = value;
}
// Example of dynamic update
setInterval(function() {
let currentValue = Math.min(100, document.getElementById('uploadProgress').value + 1);
updateProgress(currentValue);
}, 1000);
Ensuring Mobile Responsiveness
Make sure that <meter>
and <progress>
elements are responsive and display correctly on various screen sizes. Use CSS media queries to adjust the styling and layout of these elements for mobile devices.
@media (max-width: 600px) {
progress {
width: 100%;
}
}
Practical Examples and Use Cases
Implementing a Real-Time Progress Bar
One common use of the <progress>
element is for displaying real-time progress updates, such as file uploads or data processing tasks. For instance, imagine you’re developing a file upload feature where users can see the progress of their upload in real-time.
Here’s how you can implement a dynamic progress bar using JavaScript:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Real-Time Progress Bar</title>
</head>
<body>
<label for="fileUpload">File Upload:</label>
<progress id="fileUpload" value="0" max="100"></progress>
<span id="progressText">0%</span>
<input type="file" id="fileInput">
<script>
const progressBar = document.getElementById('fileUpload');
const progressText = document.getElementById('progressText');
const fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', function() {
const file = fileInput.files[0];
if (file) {
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
xhr.upload.onprogress = function(event) {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
progressBar.value = percentComplete;
progressText.textContent = Math.round(percentComplete) + '%';
}
};
xhr.onload = function() {
if (xhr.status === 200) {
progressText.textContent = 'Upload Complete!';
} else {
progressText.textContent = 'Upload Failed!';
}
};
xhr.send(new FormData().append('file', file));
}
});
</script>
</body>
</html>
In this example, the onprogress
event handler updates the <progress>
element and a <span>
element with the current upload percentage. This real-time feedback helps users track the status of their file upload.
Creating a Custom Rating System
Another practical use of the <meter>
element is to create a custom rating system. For instance, you might want to display a user rating on a product page, showing how well the product has been rated on a scale of 0 to 5.
Here’s how you could implement a simple rating system:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rating System</title>
<style>
.rating {
font-size: 1.5em;
}
.rating span {
color: gold;
}
</style>
</head>
<body>
<label for="productRating">Product Rating:</label>
<meter id="productRating" min="0" max="5" value="4">4 out of 5</meter>
<div class="rating">
<span>★</span><span>★</span><span>★</span><span>★</span><span>☆</span>
</div>
<script>
// JavaScript to dynamically update the rating display (if needed)
</script>
</body>
</html>
In this example, the <meter>
element is used to show a rating out of 5 stars, with a visual representation using Unicode star characters. The value
attribute is set to 4, indicating a high rating.
Displaying Resource Utilization
The <meter>
element can also be used to display resource utilization, such as CPU or memory usage. This is particularly useful in dashboards or monitoring applications where users need to see real-time statistics.
Here’s how you might show CPU usage:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CPU Usage</title>
</head>
<body>
<label for="cpuUsage">CPU Usage:</label>
<meter id="cpuUsage" min="0" max="100" value="45">45%</meter>
<span>45%</span>
<script>
// Example code to update CPU usage value (simulate real-time updates)
setInterval(function() {
const usage = Math.floor(Math.random() * 100); // Simulate changing CPU usage
document.getElementById('cpuUsage').value = usage;
document.querySelector('span').textContent = usage + '%';
}, 1000);
</script>
</body>
</html>
In this example, CPU usage is simulated and updated every second. The <meter>
element reflects the current usage, providing users with real-time data.
Troubleshooting Common Issues
Handling Browser Differences
Different browsers may render <meter>
and <progress>
elements differently, or some may not fully support their features. To address this, use feature detection to ensure that the elements are supported and provide fallback solutions if needed.
Accessibility Considerations
Ensure that the <meter>
and <progress>
elements are accessible to all users, including those who rely on assistive technologies. Use ARIA attributes to provide additional context and support for screen readers.
Styling and Customization
While <meter>
and <progress>
elements have default styling, you may need to customize their appearance to fit your design. Use CSS to adjust their size, colors, and other styles to match your website’s theme.
progress {
width: 100%;
height: 20px;
background-color: #eee;
border-radius: 5px;
}
progress::-webkit-progress-bar {
background-color: #f3f3f3;
}
progress::-webkit-progress-value {
background-color: #4caf50;
border-radius: 5px;
}
Advanced Techniques and Integration
Combining <meter>
and <progress>
with JavaScript
To create more interactive and dynamic user experiences, you can combine the <meter>
and <progress>
elements with JavaScript. For example, you might want to update the progress of a task or measurement based on user actions or real-time data.
Here’s how you can integrate JavaScript to control and update these elements:
Updating Progress Based on User Interaction
Imagine a scenario where you want to update the progress bar based on user input. You can use an <input>
element to adjust the value of a <progress>
bar dynamically.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interactive Progress Bar</title>
</head>
<body>
<label for="userProgress">Set Progress:</label>
<input type="range" id="userProgress" min="0" max="100" value="50">
<progress id="progressBar" value="50" max="100"></progress>
<span id="progressText">50%</span>
<script>
const rangeInput = document.getElementById('userProgress');
const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');
rangeInput.addEventListener('input', function() {
const value = rangeInput.value;
progressBar.value = value;
progressText.textContent = value + '%';
});
</script>
</body>
</html>
In this example, a range input allows users to adjust the progress value, which updates both the <progress>
element and a textual display of the percentage.
Creating Interactive Dashboards
For complex applications such as dashboards or reporting tools, you may need to combine multiple <meter>
and <progress>
elements to display various metrics and statistics.
By leveraging JavaScript, you can update these elements in real-time based on data fetched from a server or other sources.
Here’s an example of a simple dashboard that displays CPU and memory usage:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard</title>
</head>
<body>
<h1>System Dashboard</h1>
<label for="cpuUsage">CPU Usage:</label>
<meter id="cpuUsage" min="0" max="100" value="0">0%</meter>
<span id="cpuUsageText">0%</span>
<label for="memoryUsage">Memory Usage:</label>
<meter id="memoryUsage" min="0" max="100" value="0">0%</meter>
<span id="memoryUsageText">0%</span>
<script>
function updateDashboard() {
// Simulate fetching data
const cpuUsage = Math.floor(Math.random() * 100);
const memoryUsage = Math.floor(Math.random() * 100);
document.getElementById('cpuUsage').value = cpuUsage;
document.getElementById('cpuUsageText').textContent = cpuUsage + '%';
document.getElementById('memoryUsage').value = memoryUsage;
document.getElementById('memoryUsageText').textContent = memoryUsage + '%';
}
setInterval(updateDashboard, 2000); // Update every 2 seconds
</script>
</body>
</html>
In this dashboard, both CPU and memory usage are updated every 2 seconds, providing real-time feedback to users.
Integrating with Web APIs
Web APIs often provide data that can be displayed using <meter>
and <progress>
elements. For example, you can use the Fetch API to retrieve data and update the elements accordingly.
Here’s an example of fetching progress data from an API and updating a progress bar:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>API Progress</title>
</head>
<body>
<label for="apiProgress">API Progress:</label>
<progress id="apiProgress" value="0" max="100"></progress>
<span id="apiProgressText">0%</span>
<script>
function fetchProgress() {
fetch('https://api.example.com/progress')
.then(response => response.json())
.then(data => {
const progress = data.progress; // Assuming the API returns a 'progress' field
document.getElementById('apiProgress').value = progress;
document.getElementById('apiProgressText').textContent = progress + '%';
})
.catch(error => console.error('Error fetching progress:', error));
}
setInterval(fetchProgress, 5000); // Fetch progress every 5 seconds
</script>
</body>
</html>
In this example, the progress bar is updated with data fetched from an API every 5 seconds. This approach allows you to integrate real-time data into your web applications.
Performance Considerations
Optimizing for Large Data Sets
When working with large data sets or real-time updates, ensure that the updates to <meter>
and <progress>
elements are efficient. Frequent updates can lead to performance issues, so consider debouncing or throttling updates if needed.
Minimizing Reflows and Repaints
Frequent DOM updates can cause performance problems due to reflows and repaints. To minimize these, batch updates or use techniques to limit the frequency of changes.
This approach ensures smoother performance and a better user experience.
Testing Performance
Regularly test the performance of your web application, especially if it includes real-time progress updates or dynamic data. Use browser developer tools and performance profiling tools to identify and address any bottlenecks.
Ensuring Accessibility and Usability
Making <meter>
and <progress>
Accessible
Ensuring that your <meter>
and <progress>
elements are accessible to all users, including those with disabilities, is crucial. Properly implementing accessibility features ensures that your web applications are inclusive and usable by a diverse audience.
Using ARIA Attributes
ARIA (Accessible Rich Internet Applications) attributes can enhance the accessibility of <meter>
and <progress>
elements. These attributes provide additional context for users of assistive technologies, such as screen readers.
For the <meter>
element, consider using the aria-valuenow
, aria-valuemin
, and aria-valuemax
attributes to explicitly define the current value, minimum value, and maximum value. Here’s an example:
<label for="diskUsage">Disk Usage:</label>
<meter id="diskUsage" min="0" max="100" value="45" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100">45%</meter>
For the <progress>
element, similarly use ARIA attributes to provide context:
<label for="fileUploadProgress">File Upload Progress:</label>
<progress id="fileUploadProgress" value="70" max="100" aria-valuenow="70" aria-valuemin="0" aria-valuemax="100">70%</progress>
Adding Descriptive Labels
Ensure that each <meter>
and <progress>
element has a clear, descriptive label. This label should explain what the element represents and its significance. Use the <label>
element to associate text with the <meter>
and <progress>
elements.
<label for="downloadProgress">Download Progress:</label>
<progress id="downloadProgress" value="30" max="100">30% Complete</progress>
Providing Alternative Text
When the visual representation of progress or measurement alone may not be sufficient, provide alternative text or descriptions. This text should convey the purpose and status of the element to users who cannot rely on visual cues alone.
<progress id="uploadStatus" value="50" max="100" aria-label="Upload is 50% complete"></progress>
Integrating with Modern Frameworks
Using <meter>
and <progress>
with React
If you’re working with React, you can integrate <meter>
and <progress>
elements in a component-based architecture. React’s state management and rendering capabilities can be used to dynamically update these elements based on application state.
Here’s an example of a React component that uses a <progress>
element:
import React, { useState, useEffect } from 'react';
function ProgressBar() {
const [progress, setProgress] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setProgress(prev => Math.min(prev + 10, 100));
}, 1000);
return () => clearInterval(interval);
}, []);
return (
<div>
<label htmlFor="progressBar">Progress:</label>
<progress id="progressBar" value={progress} max="100">{progress}%</progress>
<span>{progress}%</span>
</div>
);
}
export default ProgressBar;
In this React component, the progress value updates every second, reflecting changes in the <progress>
element.
Implementing with Vue.js
In Vue.js, you can manage <meter>
and <progress>
elements using reactive data properties. Vue’s reactivity system allows you to easily bind data to these elements and handle updates efficiently.
Here’s an example of a Vue component with a <meter>
element:
<template>
<div>
<label for="scoreMeter">User Score:</label>
<meter id="scoreMeter" :value="score" min="0" max="100">{{ score }}%</meter>
<span>{{ score }}%</span>
</div>
</template>
<script>
export default {
data() {
return {
score: 75
};
}
};
</script>
In this Vue component, the score
data property is bound to the <meter>
element, updating its value dynamically.
Best Practices for Performance
Efficient DOM Updates
Minimize the number of DOM updates to avoid performance issues, especially when dealing with real-time data. Batch updates or use requestAnimationFrame for smooth and efficient rendering.
Optimizing for Mobile Devices
Ensure that <meter>
and <progress>
elements are responsive and display correctly on mobile devices. Use responsive design techniques to adapt the size and layout of these elements for different screen sizes.
@media (max-width: 600px) {
progress {
width: 100%;
height: 15px;
}
}
Handling Large Data Sets
For applications that handle large data sets, such as monitoring dashboards, optimize data fetching and rendering. Use lazy loading or virtual scrolling techniques to manage performance and resource usage.
Leveraging Advanced CSS for Styling
Customizing <meter>
and <progress>
Appearance
While the default styles for <meter>
and <progress>
elements are functional, they may not always align with your design needs. Advanced CSS can help you customize the appearance of these elements to better fit your website’s aesthetic.
Styling the <progress>
Element
The <progress>
element can be styled using pseudo-elements to create a more visually appealing design. The ::-webkit-progress-bar
, ::-webkit-progress-value
, and ::-moz-progress-bar
pseudo-elements allow you to customize the progress bar’s background and fill.
progress {
width: 100%;
height: 20px;
border-radius: 5px;
background-color: #eee;
}
progress::-webkit-progress-bar {
background-color: #f3f3f3;
}
progress::-webkit-progress-value {
background-color: #4caf50;
border-radius: 5px;
}
progress::-moz-progress-bar {
background-color: #4caf50;
border-radius: 5px;
}
In this example, the progress bar’s background and fill colors are customized to fit a green theme with rounded corners.
Styling the <meter>
Element
Customizing the <meter>
element is more limited, as it is primarily designed for displaying measurements and lacks the extensive pseudo-element support of <progress>
. However, you can use CSS to style its container and provide additional context.
meter {
width: 100%;
height: 20px;
border-radius: 5px;
background-color: #eee;
}
meter[value="0"] {
color: red;
}
For more complex styling, consider wrapping the <meter>
element in a container and applying custom styles to both the container and the meter.
<div class="meter-container">
<meter id="batteryLevel" min="0" max="100" value="75">75%</meter>
</div>
<style>
.meter-container {
width: 100%;
height: 25px;
background-color: #f0f0f0;
border-radius: 5px;
padding: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
}
meter {
width: 100%;
height: 100%;
border-radius: 5px;
}
</style>
This approach allows you to use CSS to enhance the visual appeal of the <meter>
element by adding shadows and padding.
Creating Animations and Transitions
Animations and transitions can make the <meter>
and <progress>
elements more engaging and dynamic. CSS transitions and animations can be used to smoothly update the values and provide visual feedback.
Adding Transitions to <progress>
Transitions can be applied to the <progress>
element to create a smooth effect when the value changes. For instance:
progress {
width: 100%;
height: 20px;
border-radius: 5px;
background-color: #eee;
transition: width 0.5s ease;
}
progress::-webkit-progress-bar {
background-color: #f3f3f3;
}
progress::-webkit-progress-value {
background-color: #4caf50;
border-radius: 5px;
}
In this example, the width
property transitions smoothly, enhancing the visual experience when the progress value changes.
Creating Animated <meter>
Elements
Animations can be added to <meter>
elements to highlight changes or draw attention to specific values. For example, use keyframe animations to create a pulsing effect:
@keyframes pulse {
0% {
background-color: #4caf50;
}
50% {
background-color: #66bb6a;
}
100% {
background-color: #4caf50;
}
}
meter {
width: 100%;
height: 20px;
border-radius: 5px;
animation: pulse 1.5s infinite;
}
This keyframe animation creates a pulsing effect on the <meter>
element, drawing attention to changes in the measurement.
Security Considerations
Handling User Input
When using <meter>
and <progress>
elements to display or update values based on user input, ensure that the input is properly validated and sanitized. This is crucial to prevent malicious input and maintain the integrity of your application.
Validating Data
Always validate user input to ensure it falls within expected ranges. For example, if you allow users to input progress values, check that the values are within the range defined by your <meter>
or <progress>
element.
function validateInput(value) {
return Number.isInteger(value) && value >= 0 && value <= 100;
}
const inputValue = 50; // Example user input
if (validateInput(inputValue)) {
document.getElementById('progressBar').value = inputValue;
}
Protecting Against XSS Attacks
Be cautious of Cross-Site Scripting (XSS) attacks when dynamically updating the content or attributes of <meter>
and <progress>
elements. Avoid injecting untrusted data directly into the DOM.
Escaping Data
When inserting data into your application, always escape special characters to prevent XSS attacks. For example, use built-in methods or libraries that handle escaping.
function escapeHTML(text) {
const element = document.createElement('div');
element.innerText = text;
return element.innerHTML;
}
const safeText = escapeHTML('<script>alert("XSS")</script>');
document.getElementById('progressText').innerHTML = safeText;
Ensuring Secure Data Handling
If your application involves sensitive data, such as progress updates related to secure processes, ensure that data is transmitted over secure channels (e.g., HTTPS) and is properly encrypted.
Testing and Debugging
Cross-Browser Testing
Ensure that <meter>
and <progress>
elements are tested across different browsers and devices to verify consistent behavior and appearance. Tools like BrowserStack or manual testing can help identify and address cross-browser compatibility issues.
Debugging JavaScript and CSS
Use browser developer tools to inspect and debug JavaScript and CSS related to <meter>
and <progress>
elements. These tools can help you identify issues with element rendering, updates, and interactions.
Performance Profiling
Monitor and profile the performance of your application to identify any performance bottlenecks related to the <meter>
and <progress>
elements. Use browser performance profiling tools to analyze and optimize your implementation.
Final Insights and Recommendations
Staying Updated with Web Standards
Web standards and best practices evolve rapidly. Stay informed about the latest updates to HTML5, CSS, and JavaScript to ensure that your implementation of <meter>
and <progress>
elements remains up-to-date and takes advantage of new features and improvements.
Follow official web standards organizations like W3C and WHATWG, and keep an eye on browser release notes.
Leveraging Community Resources
The web development community is a valuable resource for learning and troubleshooting. Engage with forums, attend webinars, and follow influential developers on social media to gain insights and share knowledge about using <meter>
and <progress>
elements effectively.
Platforms like Stack Overflow, MDN Web Docs, and CSS-Tricks offer a wealth of information and practical advice.
Continuous User Testing
Conduct regular user testing to gather feedback on how <meter>
and <progress>
elements are used in your application. User feedback can reveal usability issues, accessibility challenges, and areas for improvement.
Implementing changes based on user testing helps ensure that your design choices align with user needs and expectations.
Documentation and Best Practices
Document your implementation of <meter>
and <progress>
elements thoroughly. Provide clear guidelines and examples for your team or future developers who may work on your project.
Well-documented code and design practices contribute to maintainability and consistency across your projects.
Experimentation and Innovation
Don’t be afraid to experiment with new techniques and approaches when using <meter>
and <progress>
elements. Innovation often involves trying out new ideas and solutions, which can lead to unique and effective user experiences.
Keep experimenting with CSS styles, JavaScript interactions, and integrations to discover creative ways to enhance your applications.
Wrapping it up
The HTML5 <meter>
and <progress>
elements offer powerful ways to display measurements and progress on web pages. They enhance user experience by providing visual feedback on various metrics, from task completion to system performance.
Effective use of these elements involves adhering to best practices for accessibility, styling, and performance. By leveraging CSS for customization, integrating JavaScript for dynamic updates, and ensuring security and cross-browser compatibility, you can create engaging and functional user interfaces.
Remember to stay updated with web standards, seek feedback through user testing, and continuously explore new techniques to improve your implementations. By following these guidelines, you’ll create web applications that are not only visually appealing but also user-friendly and robust.
READ NEXT: