skip to Main Content

I have a box in the top left corner of a document. I want to rotate it using a transform so that one of its edges is pointing toward the lower right corner of the viewport. Based on my reading of the relevant specs, this seems like it ought to work.

html, body {
  margin: 0;
  padding: 0;
}

#oriented {
  position: absolute;
  width: 100px;
  height: 100px;
  top: 0;
  left: 0;
  outline: solid black 2px;
  transform-origin: top left;
  transform: rotate(atan2(100vh, 100vw));
}
<div id="oriented"></div>

However, it doesn’t work as expected. Firefox doesn’t rotate the box at all. Chrom-ish browsers put it at a fixed 45° angle, regardless of viewport. Is there any way to get this working? Is this a bug in the browsers, or am I misunderstanding the specs?

2

Answers


  1. Dividing two lengths to get a number is something defined in the Spec but has no support yet so your code may work in the future but not now.

    You can try calc(50vw/100vw) which actually invalid but in the future it should give you 0.5

    .box {
      background: red;
      height: 100px;
      opacity: calc(50vw/100vw); /* inspect the code to see it's invalid */
    }
    <div class="box"></div>

    Same logic with your code since atan2(100vh, 100vw) is equivalent to atan(100vh/100vw).

    it seems that chrome is doing the effort to convert your code into something valid but it’s clearly not the expected result.

    Login or Signup to reply.
  2. Although it may not make much of a difference here, but the values assigned to atan2(100vh, 100vw) seemed reversed in that the horizontal axis x is the first value and the vertical axis y is the second value wherein x = 100vh and y = 100vw vh is normally associated with y and vw with x. Also, if you use an absolute positioned element, it’s easier to position it within an element with position: relative. One more thing is that transform-origin is in relation to the position of the element being transformed so it’s been changed to center center.

    I don’t know exactly what you’re objective is so I made an interactive example so you can adjust x and y on the fly.

    /**
     * While vw and vh units are great for lengths relative to   
     * viewport, they are different as far as being units.  
     * Typical desktop viewport is 16:9 so if width is 100vw then a
     * compatable height would be 56.25vw.
     */
    const atan2 = (x, y) => Math.atan2(y, x) * 180 / Math.PI;
    
    document.forms.ui.oninput = rotate;
    
    function rotate(e) {
      const fc = this.elements;
      let x = fc.x1.value;
      let xu = fc.x2.value;
      let y = fc.y1.value;
      let yu = fc.y2.value;
      let deg = fc.deg;
    
      const sq = document.querySelector(".square");
      sq.style.cssText = `transform: rotate(atan2(${x+xu}, ${y+yu}));`
      deg.value = atan2(x, y).toFixed(2) + '°';
    }
    :root {
      font: 5vmin/1 Consolas;
    }
    
    html,
    body {
      margin: 0;
      padding: 0;
    }
    
    .viewport {
      position: relative;
      width: 90vw;
      min-height: 90vh;
      margin: 20px auto;
      outline: 3px dashed red;
    }
    
    .square {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      width: 100px;
      height: 100px;
      top: 0;
      left: 0;
      outline: 2px solid black;
      transform-origin: center center;
      transform: rotate(atan2(100vw, 100vh));
    }
    
    #ui {
      position: absolute;
      bottom: 0;
    }
    
    label {
      display: inline-flex;
      align-items: center;
      width: 40vw;
    }
    
    label:nth-of-type(odd) {
      justify-content: flex-end;
    }
    
    label:nth-of-type(even) {
      justify-content: flex-start;
    }
    
    input {
      width: 10ch;
      font: inherit;
      text-align: center;
    }
    
    output {
      font-size: 2rem;
    }
    <main class="viewport">
      <section class="square">
        <output id="deg" form="ui"></output>
      </section>
      <form id="ui">
        <label>X: <input id="x1" type="number" value="0"></label>
        <label>unit: <input id="x2"></label><br>
        <label>Y: <input id="y1" type="number" value="0"></label>
        <label>unit: <input id="y2"></label>
      </form>
    </main>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search