{"componentChunkName":"component---src-templates-post-jsx","path":"/blog/the-css-transform-property-and-individual-transforms-are-additive/","result":{"data":{"mdx":{"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"title\": \"The CSS Transform property and individual transforms are additive\",\n  \"cover\": \"/blogs/transformsadditive/cover.svg\",\n  \"date\": \"2025-02-20\",\n  \"type\": [\"tutorial\"]\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `Here's something you might not know: the CSS `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `transform`), ` and individual transform properties (`, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `translate`), `, `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `rotate`), ` and `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `scale`), `) are additive. If you set both, the values are all added together to determine the final transformation.`), mdx(\"h2\", {\n    \"id\": \"css-properties-overwrite-each-other\"\n  }, `CSS properties overwrite each other`), mdx(\"p\", null, `If you first set a font-size in a `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `font`), ` property and then set a different font-size in a `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `font-size`), ` property, that `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `font-size`), ` overwrites the `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `font`), ` property:`), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"css\"\n  }, mdx(\"pre\", _extends({\n    parentName: \"div\"\n  }, {\n    \"className\": \"language-css\"\n  }), mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-css\"\n  }), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token selector\"\n  }), `body`), ` `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `{`), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token property\"\n  }), `font`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `:`), ` 16px system-ui`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `;`), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token property\"\n  }), `font-size`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `:`), ` 20px`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `;`), `\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `}`), `\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token comment\"\n  }), `/* resulting font is system-ui in 20px */`)))), mdx(\"p\", null, `Likewise, if you set a `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `border-top`), `, and then set a `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `border-color`), `, the color of your `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `border-top`), ` will be overwritten.`), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"css\"\n  }, mdx(\"pre\", _extends({\n    parentName: \"div\"\n  }, {\n    \"className\": \"language-css\"\n  }), mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-css\"\n  }), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token selector\"\n  }), `body`), ` `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `{`), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token property\"\n  }), `border-top`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `:`), ` 5px solid red`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `;`), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token property\"\n  }), `border-color`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `:`), ` blue`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `;`), `\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `}`), `\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token comment\"\n  }), `/* resulting border-top is 5px solid blue */`)))), mdx(\"p\", null, `In CSS the behavior is that `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `properties that affect the same thing will overwrite each other`), `.`), mdx(\"p\", null, `But with CSS `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `transform`), ` and the individual transform properties, the values are added together instead, why?`), mdx(\"h2\", {\n    \"id\": \"the-css-transform-property\"\n  }, `The CSS transform property`), mdx(\"p\", null, `The `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `transform`), ` property lets you transform elements in different ways, for example by translating them (moving them around in x/y/z), scaling them, rotating them, skewing them, etc. You can set multiple transformations at once, by separating them with spaces. For example:`), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"css\"\n  }, mdx(\"pre\", _extends({\n    parentName: \"div\"\n  }, {\n    \"className\": \"language-css\"\n  }), mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-css\"\n  }), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token property\"\n  }), `transform`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `:`), ` `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token function\"\n  }), `translate`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `(`), `10px`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `,`), ` 20px`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `)`), ` `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token function\"\n  }), `rotate`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `(`), `45deg`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `)`), ` `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token function\"\n  }), `scale`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `(`), `2`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `)`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `;`)))), mdx(\"p\", null, `This is powerful because the order matters: you can `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `translate`), ` and then `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `rotate`), `, or `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `rotate`), ` and then `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `translate`), `, and you'll get different results:`), mdx(OrderingExample, {\n    mdxType: \"OrderingExample\"\n  }), mdx(\"p\", null, `This powerful API also means that if you want to change one of the transformations, you have to set all of them again or they get overridden.`), mdx(\"p\", null, `If you have a rotated element that you want to scale up on hover, you will `, mdx(\"em\", {\n    parentName: \"p\"\n  }, `also`), ` need to rotate that element again in the hover state, or the rotation will be lost. Try hovering over the element below, for example:`), mdx(Ordering2Example, {\n    mdxType: \"Ordering2Example\"\n  }), mdx(\"p\", null, `The element scales in, but you lose the rotation.`), mdx(\"h2\", {\n    \"id\": \"individual-transform-properties\"\n  }, `Individual transform properties`), mdx(\"p\", null, `That's where the individual properties come in: they let you set, and re-set, each transformation separately.`), mdx(\"p\", null, `For example, you can set the `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `translate`), ` property to move an element around, and then set the `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `scale`), ` property on hoverto scale it up, without losing the translation:`), mdx(IndividualExample, {\n    mdxType: \"IndividualExample\"\n  }), mdx(\"h2\", {\n    \"id\": \"additive-transforms\"\n  }, `Additive transforms`), mdx(\"p\", null, `If you set both `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `transform`), ` and individual transform properties on an element, the transforms are additive. This means that all the transform values are added together to determine the final transformation.`), mdx(\"p\", null, `In the example below, both elements have a `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `transform`), `, but the second element also has a `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `translate`), `. You can edit the CSS below to see how the total translation changes.`), mdx(AdditiveExample, {\n    mdxType: \"AdditiveExample\"\n  }), mdx(\"p\", null, `This specific behavior is described in the CSS transforms specification under paragraph 6: `, mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://www.w3.org/TR/css-transforms-2/#ctm\"\n  }), `Current Transformation Matrix`), `.`), mdx(\"p\", null, `That explainer is for browsers so it's a bit technical. If we omit the non-transform properties, the order of the transformations is as follows:`), mdx(\"ol\", null, mdx(\"li\", {\n    parentName: \"ol\"\n  }, `Apply the `, mdx(\"code\", _extends({\n    parentName: \"li\"\n  }, {\n    \"className\": \"language-text\"\n  }), `translate`), ` property`), mdx(\"li\", {\n    parentName: \"ol\"\n  }, `Apply the `, mdx(\"code\", _extends({\n    parentName: \"li\"\n  }, {\n    \"className\": \"language-text\"\n  }), `rotate`), ` property`), mdx(\"li\", {\n    parentName: \"ol\"\n  }, `Apply the `, mdx(\"code\", _extends({\n    parentName: \"li\"\n  }, {\n    \"className\": \"language-text\"\n  }), `scale`), ` property`), mdx(\"li\", {\n    parentName: \"ol\"\n  }, `Apply the `, mdx(\"code\", _extends({\n    parentName: \"li\"\n  }, {\n    \"className\": \"language-text\"\n  }), `transform`), ` functions from left to right`)), mdx(\"p\", null, `So now you know too: the `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `transform`), ` and individual transform properties are additive. If you set both, the total translation combines everything you've set.`), mdx(\"p\", null, `If you want a more in-depth, step-by-step explainer of the CSS transformation matrix, this recent post by Schalk Neethling is a great resource: `, mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://schalkneethling.com/posts/css-transforms-and-the-matrix/#the-css-transform-matrix\"\n  }), `CSS transforms and the matrix`)), mdx(\"h2\", {\n    \"id\": \"video-by-frontendfyi\"\n  }, `Video by FrontendFYI`), mdx(\"p\", null, `Jeroen Reumkens from FrontendFYI has a great video about this topic and how it relates to changes in Tailwind CSS 4, so if you prefer video check it out:`), mdx(\"div\", {\n    \"className\": \"gatsby-resp-iframe-wrapper\",\n    \"style\": {\n      \"paddingBottom\": \"56.25%\",\n      \"position\": \"relative\",\n      \"height\": \"0\",\n      \"overflow\": \"hidden\"\n    }\n  }, ` `, mdx(\"iframe\", _extends({\n    parentName: \"div\"\n  }, {\n    \"src\": \"https://www.youtube-nocookie.com/embed/tdip011nNGk?si=iLvxswzB3G-U7rDU\",\n    \"title\": \"YouTube video player\",\n    \"frameBorder\": \"0\",\n    \"allow\": \"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\",\n    \"referrerPolicy\": \"strict-origin-when-cross-origin\",\n    \"allowFullScreen\": true,\n    \"style\": {\n      \"position\": \"absolute\",\n      \"top\": \"0\",\n      \"left\": \"0\",\n      \"width\": \"100%\",\n      \"height\": \"100%\"\n    }\n  })), ` `), mdx(\"p\", null, `Don't forget to like the video if it was useful! ;)`));\n}\n;\nMDXContent.isMDXComponent = true;","timeToRead":2,"tableOfContents":{"items":[{"url":"#css-properties-overwrite-each-other","title":"CSS properties overwrite each other"},{"url":"#the-css-transform-property","title":"The CSS transform property"},{"url":"#individual-transform-properties","title":"Individual transform properties"},{"url":"#additive-transforms","title":"Additive transforms"},{"url":"#video-by-frontendfyi","title":"Video by FrontendFYI"}]},"excerpt":"Here's something you might not know: the CSS  transform  and individual transform properties ( translate ,  rotate  and  scale ) are additive. If you set both…","frontmatter":{"title":"The CSS Transform property and individual transforms are additive","cover":"/blogs/transformsadditive/cover.svg","date":"2025-02-20","updated":null},"fields":{"slug":"/blog/the-css-transform-property-and-individual-transforms-are-additive/","date":"2025-02-19T23:00:00.000Z","ogFileName":"the-css-transform-property-and-individual-transforms-are-additive"}}},"pageContext":{"slug":"/blog/the-css-transform-property-and-individual-transforms-are-additive/"}},"staticQueryHashes":["4164364741","425175329"]}