Webdev WTF
Tags: webdev, css, html, w3c
Published: 2020-12-17 13:36:19

---
title: Webdev WTF
published: true
description: Have you ever hit a strange issue while doing frontend development and said WTF? Post here
tags: webdev, CSS, HTML, w3c
//cover_image: https://direct_url_to_image.jpg
---

Have you ever hit a strange issue while doing frontend development and said WTF?

I thought it might be interesting to share these WTF moments and maybe learn something from each other and have a little laugh.

Here are some of the WTFs I've encountered in my 10+ years of frontend development.

## `document.querySelectorAll` does not return an actual array

`document.querySelectorAll` does not return an actual array, but a `NodeList` instance that only _partially_ acts like an array: `typeof document.querySelectorAll('a').map === 'undefined'`

`NodeList` has `#forEach` method, but doesn't have `#map` method. It's a mess. :)

## Getting CSS styles of a DOM element in JS

There's `el.style`, but that only works for inline styles in HTML: `<div style="...">`. Then there's the _global_ `getComputedStyle(Element, pseudo)` which almost works, but not quite (depending on what you need):

```css
body > .container {
  background: none;
}
```

```js
getComputedStyle(containerEl).background
// => "rgba(0, 0, 0, 0) none repeat scroll 0% 0% / auto padding-box border-box"
```

This happens because `background` is a shorthand property for many other properties (such as `backgroundColor`, etc.)
What if I want to get the exact CSS style from the CSS? I personally have no idea how to do that.

## Super complicated to get URL params

`window.location` is not a string. It's not a `URL` either. It's...`Location`. Let's see how we could get the URL params.
An instance of `URL` class has: `searchParams` method. We can create a `URL` instance from `Location`:

```js
// imagine window.location is https://example.com/events/new?premium=true#buy
const url = new URL(window.location)
const whyIsThisCalledSearchParams = url.searchParams
whyIsThisCalledSearchParams.toString() // => "premium=true"
```

IT WORKS!!!! 😍

Not so fast, Mr. Gordon.

```js
JSON.stringify(whyIsThisCalledSearchParams) // => "{}"
// WAT
```

Ok, well, there's `#entries()` method. I guess that's like `Object.entries()`, right? Let's use that:

```js
Object.entries({ name: 'Viktor' })
// => [["name", "Viktor"]]
whyIsThisCalledSearchParams.entries()
// => Iterator {}
// WAT it's empty
Object.entries(new URL(location).searchParams)
// => []
// WAT it's empty
```

```js
whyIsThisCalledSearchParams.get('premium')
// => "true"
// of course, true is a string here, but that's ok
```

The only way to get the url query parameters:

```js
for (const [key, value] of whyIsThisCalledSearchParams) {}
```

Or you can do the old-fashioned way:

```js
// because first character is "?" because why not :)
const query = window.location.search.substring(1)
query.split('&').....each(queryPair => queryPair.split('='))
```

And then you hope you won't need arrays in there...I also forgot to mention parsing any special characters...sorry! :)

Also, `searchParams` is called [query](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier) in the official RFCs. To me, "query" or "query params" make more sense than "search params".

## In JavaScript you can't get all form field values through standard API

`formEl.formValues` or similar doesn't exist. You have to do: `formEl.querySelectorAll('input, select').map(el => el.value)`. But that won't work for several reasons. First, you can't use `.map`, but we'll get to that in a moment.
Second, you can have input fields outside of the `formEl`:

```html
<input type="text" form="editform" name="id">

<form action="datamanager" id="editform"></form>
```

This works.

So you need to do all this extra mumbo jumbo similar to this:

```js
formEl.querySelectorAll('input, select').forEach(el => {
  if (el.type === 'checkbox' || el.type === 'radio') {
    el.checked
  } else {
    el.value
  }
}
if (formEl.id) {
  document.querySelectorAll('input[form="' + formEl.id + '"]').forEach(...)
}
```

I lied. You can get the form values using the `FormData` class and its `#entries()` method. Maybe.
It might work, but it might fail silently (which is the worst possible way to fail, when you don't know it failed) if you decide to add an input element outside of the form tag programmatically:

```js
const inputEl = document.createElement('input')
inputEl.name = 'firstName'
inputEl.form = 'customerForm'
inputEl.form
// => null
// WAT it just fails silently
inputEl.setAttribute('form', 'customerForm')
// => works as expected
```

## `dataset` vs `data-*` vs `dataset.kebabCase` vs `data-kebab-case`

In HTML you write: `data-target-id="someid"`, while in JavaScript, to get that same attribute value, you say: `el.dataset.targetId`. WAT.

## CSS _usually_ (on a good day) prefers class names with kebab case, but JS prefers pascalCase:

```css
.container {
  background-color: #ffffff;
`
```

```js
containerEl.style.backgroundColor = '#ffffff'
```

Also check these great examples:

```css
div {
  display: inline-block; /* kebab case, as the rest of the CSS */
  white-space: nowrap; /* nowrap? WAT no-wrap? WAT */
}
```

How about this:

```css
button {
  white-space: nowrap;
}
div {
  white-space: no-pre; /* What the... 🤯 */
}
```

## Getting element's X/Y position on the page from page top

This works:

```js
el.getBoundingClientRect().top + window.pageYOffset
```

Or does it?

Well, sort-of. It works if the element is not in a inside some container that's position fixed. So you first have to find check all of the element's ancestors to see if any one of those is position fixed and only then you can calculate this correctly. Please correct me if I'm wrong here. I'd love to be wrong here.

## Does this look familiar: `z-index: 9999999999999999`?

You add `z-index: 9999999999999999` to an element, but it's still not above all the other elements. Y U NO?
It's because `z-index` is "stacking". So it works kind of like this:

```html
<div id="header" style="z-index: 2"></div>
<div id="main-content" style="z-index: 1">
  <div id="dis-one" style="z-index: 999"></div>
</div>
```

The `#dis-one` element has an overall z-index of 1.999, while `#header` has an overall z-index of 2. It stacks.

Well, yeah...maybe. But not always.

First of all, you need to add at least `position: relative` for `z-index` to have any effect. Secondly, new stacking contexts are also created when you apply a `transform`. So, sometimes to show `.container:before` behind `.container` you need to actually add another HTML element (let's call it) `.wrapper` around `.container`.

Check out this answer:
https://stackoverflow.com/a/20852489/336806

## `<input type="submit">` and `<button>`

There's a special input type called "submit", which _kind-of_ renders like a button. It also has a `value` attribute, but it's _usually_ not submitted to the backend. Remember our code for getting form values? Well, it does submit this value. That's another edge case you need to take care of.
It's also far more limiting than an actual `<button>`

Speaking of `<button>`:

## The `<button>`

Here's a part of a website's HTML:

```html
<button>Submit</button>
```

...but it's not working. 🤔 The form doesn't get submitted when you click on this button.

You know that `button`'s default type is `type="submit"`. And you see no JavaScript code that could prevent the submission.
Then you realize, you put it outside of the `<form>`:

```html
<form>
  <!-- form fields -->
</form>
<button>Submit</button>
```

Well, if the `<button>` tag is placed outside of `<form>` tag, it behaves pretty much like `<button type="button">`.
It's the same HTML syntax that acts differently whether it's inside of `<form>` tag or not.

Similary, this is also a disaster in the making:

```html
<form action="/events">
  <form action="/events/5">
    <button>Submit</button>
  </form>

  <button>Submit</button>
</form>
```

Similarly:

```html
<label>
  <input type="checkbox" name="terms">
  I accept the <a href="/terms">Terms & Conditions</a>
</label>
```

Or (these examples are not for faint hearted):

```html
<a href="/events/5">
  <div>Best Ice-cream in town</div>
  <a href="/events/5/more-info">
    More info about Ice-cream party
  </a>

  <button>Submit</button>
</a>
```

## Let's talk some more about JavaScript

```js
typeof [] === 'object' // WAT
typeof null === 'object' // WAT
typeof undefined === 'undefined' // WAT
```

```js
const add = (a = 1, b = 2) => {
  if (a && b) {
    return a + b
  } else {
    return 0
  }
}
add(undefined, undefined) === 3 // hmmm...ok
add(2, null) === 0 // WAT
add(3, undefined) === 5 // WAT
```

I'll wrap up here. Please do share your experiences working on frontend. :) Thanks!