Get Elements by Style

MediumZepto

Prompt

Could you implemenet a function called getElementsByStyle that takes in an element, a property string, and a value string representing the style's property/value pair to be matched on the elements descendants. E.g. getElementsByStyle(document.body, 'font-size', '20px'). This function does not exist natively in the DOM API. However, we would like to build it as part of our interview today.

Example

<main>
<div>
<p style="font-weight: bold;">Bold Paragraph</p>
<p style="font-size: 20px;">Large Paragraph</p>
</div>
</main>
const elements = getElementsByStyle(document.body, 'font-weight', 'bold');
console.log(elements); // [p]
Hint 1

You can use window.getComputedStyle(element) to retrieve the computed style of an element. This returns a CSSStyleDeclaration object containing all the element's computed styles. You can take a look at the MDN docs for more details about this object.

Hint 2

The computedStyles object has a getPropertyValue method that can be used to retrieve the value of a specific property. You can check this value against the value parameter to determine if the element matches the style criteria. If it does, you can add the element to the result array and return the array at the end of the function.

Solution

Explanation

The getElementsByStyle function allows us to search the DOM for elements with specific computed style values, a capability not natively provided by the DOM API.

Understanding the Problem

Our implementation of getElementsByStyle does the following:

  • Searches through DOM elements to find those with a specific CSS property value
  • Returns all matching elements as an array
  • Only includes descendants of the starting element (not the element itself)

Our solution leverages the getComputedStyle method and the getPropertyValue method of the CSSStyleDeclaration object.

The Window.getComputedStyle() method returns an object containing the values of all CSS properties of an element, after applying active stylesheets and resolving any basic computation those values may contain.

// window.getComputedStyle() - Returns the computed style of an element
const computedStyles = getComputedStyle(el);

// CSSStyleDeclaration.getPropertyValue() - Gets the value of a specific CSS property
const propertyValue = computedStyles.getPropertyValue(property);

DOM Traversal with Style Checking

function traverse(el) {
if (el == null) {
return;
}

const computedStyles = getComputedStyle(el);
if (computedStyles.getPropertyValue(property) === value) {
elements.push(el);
}

for (const child of el.children) {
traverse(child);
}
}

The traverse function implements a depth-first search of the DOM tree.

  • It checks if the current element's computed style for the specified property matches our target value
  • If it matches, it adds the element to our results array
  • Then it recursively processes each child element

Important Considerations with Computed Styles

A crucial aspect of working with getComputedStyle() is understanding that it returns browser-calculated final values:

  1. CSS keywords are often converted to their computed equivalents:
    • font-weight: bold becomes "700"
    • color: red becomes "rgb(255, 0, 0)" or similar
  2. Relative units are converted to absolute values:
    • 2em might become "32px" depending on the context
    • Percentages are typically calculated into pixels

This explains why in our test case, we're matching 'font-weight' with '700' rather than 'bold' because that's how the browser represents it internally.

Starting with Children

We start by iterating through the children of the input element:

for (const child of element.children) {
traverse(child);
}

This ensures we don't include the root element itself in our results, matching the behavior of native DOM methods like getElementsByTagName.

00:00