By Rich Guzikowski, Software Developer
Viewer feedback is a critical part of Hulu’s iterative process and helps us immensely when determining what features to prioritize and ship. Several features have started their lives as suggestions from viewers, with the most recent being Night Mode on hulu.com.
Initially prompted by a Reddit request, Night Mode (or dark theme) is a feature our development team discussed several months before the launch of the new Hulu.com. We recognized how jarring a bright white background can be when watching Hulu in darker environments, so a few members of our team were inspired to pursue Night Mode as a hackathon project in August. After winning the hackathon’s “Most Likely to Ship” award, our team focused on developing an approach for long-term maintainability so that Night Mode styles could be applied to all future pages with little ongoing effort from developers, UX, and QA.
Although building night mode for our existing website was not a huge technical challenge, there were some important requirements we considered when working on this feature:
- Look and Feel — We work closely with UX on all user-facing features for the site, and this project was no exception. To create a Night Mode color palette to correspond to existing colors on the site, we collaborated with the Hulu UX team to review the colors of all the elements on the site to see what elements needed corresponding Night Mode colors. Once all these elements were identified, we had to experiment with the styles in the browser to determine which colors to use for Night Mode
- Persistence of Night Mode Preferences — Instead of requiring a user to turn on Night Mode upon every new session to the site, we wanted to be able to remember a user’s preferences with regards to night mode. In order to accomplish this, we decided that we would need to either A) Modify our existing User API to store Night Mode preferences for each user in our backends, or B) store the Night Mode preferences in browser Local Storage. In the end, we decided to go with the latter option for ease of implementation.
- Ease of Implementation / Maintainability — Our repository has thousands of lines of SCSS used to style the various components on our site. So, it was essential to our team that our Night Mode implementation add styles to a place that’s simple to maintain and keep additional styles to a minimum. This played a major factor in determining how we implemented this feature.
React Context + Night Mode Specific ClassNames
Our initial approach to build Night Mode was to make use of React’s context api. Unlike React props, which must be manually passed through each level to reach children components, values stored in the context api can be accessed at any level of the component hierarchy. This makes it ideal for common values that are used in various parts of the application, and in fact in the Context docs, UI themes are one of the example use cases. The approach was as follows:
- Create a Night Mode Context that keeps track of the status of the Night Mode Switch
- Create a provider for the Context at or root level page component: This component would keep a local state variable for tracking whether night mode was on or off, and then provide the variable as the value for the Night Mode Context
- Refactor some of our React components to be Context Consumers: Context Consumers provide us with a way to subscribe to Context changes. In a similar pattern to React’s render props, the Consumer component wraps a function for which the value argument is passed the Context value. The function body then renders a React Node, whose composition is dependent on this value argument
- Use the Classnames library to conditionally apply a Night Mode className based on the Night Mode Context value: We use the BEM (Block Element Modifier) naming convention for classnames, and therefore to add a NightMode class we would just append “ — night” (a Modifier) to the normal class name.
- Apply necessary css styles to the the Night Mode classes (change background color from black to white, etc..)
Although this implementation worked when creating the hackathon project for this feature, we found it tedious to implement in production, and it had a high probability of becoming a maintenance burden. For one, using this approach meant that we had to refactor every component that needed Night Mode styling. We had to wrap all these components within the NightModeContext Consumer and then also apply Night Mode class names. Additionally, this meant that for each additional feature we implemented, we would have to write CSS styles for both the Night Mode theme and regular theme. This led our team of developers to explore another possible option, CSS Custom Properties, to allow for better development maintainability.
CSS Custom Properties
CSS Custom Properties, also referred to as CSS variables, allow for styling values such as hex colors or font sizes to be reused throughout a webpage. For our purposes of Night Mode Styling, we decided we could refactor CSS to use CSS variables in all the places we used colors. Then we could simply change the values of these variables whenever the Night Mode Switch was toggled. Here is a more in-depth explanation of the implementation strategy.
- Refactor some of our CSS common colors from SCSS variables and into CSS custom properties with generic names: For example, many of our text elements on the site share the same color, #292C33. Therefore we created a CSS variable with that value in called — text — primary
- Come up with complimentary Night Mode colors for each newly created CSS variables.
- Attached all these CSS custom properties (both for Night Mode and the regular theme) to the HTML Body element
- Upon togging the Night Mode Switch, add a “night” class to the document body
- Override these CSS custom properties to specified Night Mode values when the “night” class is present
This approach proved to be much simpler to implement, allowing us to change the colors of multiple elements on the site simply by changing the value of a single CSS variable. Additionally, for future UI elements we can make use of these pre-created variables, allowing us to implement night mode styling without additional work.
Although it took us a couple iterations to get right, we feel that we finally settled on a Night Mode implementation that’s flexible, requires little maintenance for future development, and most importantly, looks great in the browser. Moreover, the development of this feature showed us that there is more than one way to get the job done. This isn’t so much of a learning, but reinforced a common idea in software development — just because a piece of software or feature works, doesn’t mean that it should be the implemented for the final product. It’s always important to consider maintainability of the code base, so that you can minimize the introduction of technical debt.
The next time you find yourself browsing Hulu.com late at night, don’t forget to check out Night Mode. All you have to do is toggle the Night Mode switch found in the profile menu dropdown. Your eyes will thank you!
If you’re interested in working on projects like these and powering play at Hulu, see our current job openings here.