首頁  >  文章  >  web前端  >  解碼 StyleX:Meta 的尖端造型系統

解碼 StyleX:Meta 的尖端造型系統

Susan Sarandon
Susan Sarandon原創
2024-11-10 21:32:02745瀏覽

每年十月,最大的國際 React 會議都會在印度果阿舉行。是的,我說的是 React India。今年(2024 年)對我來說更加特別,因為我有機會在這場盛大的會議上發言。如果你錯過了現場觀看的話,這是我的演講錄音。如果您喜歡閱讀而不是觀看視頻,那麼這個部落格非常適合您!讓我們深入探討一下。

什麼是 StyleX?

StyleX 是 Meta 的新的、可擴展的樣式庫,現在被用作 Facebook、Instagram 和 WhatsApp 等平台背後的主要係統。它解決了 CSS-in-JS 方法所遇到的痛點,特別是在大規模 React 應用程式中。透過提供融合原子 CSS 和靜態 CSS 最佳功能的混合解決方案,StyleX 提供了高效、模組化和可擴展的替代方案。

Meta 如何以及為何創建 StyleX?

  • Meta 建立 StyleX 來解決傳統 CSS-in-JS 庫在大型專案中遇到的特定挑戰:
  1. 未使用的樣式:隨著項目的成長,CSS 經常會累積未使用的規則,使樣式表變得臃腫。
  2. 效能問題: CSS-in-JS 解決方案可能會導致 CSS 檔案過大或出現效能瓶頸,尤其是與應用程式捆綁在一起時。
  3. CSS-in-JS 庫大小: 許多用於 JavaScript 樣式的流行庫為套件添加了不必要的重量,影響了載入時間。
  • StyleX 簡介:它於 2019 年創建,作為 Facebook UI 改造的一部分,並於 2023 年 12 月將其開源。
  • CSS 最佳化:在使用 StyleX 之前,Facebook 上的單一頁面將載入大約 15-45MB 的 CSS 樣式。透過利用單一 CSS 捆綁包,StyleX 的大小大大減少到 200-300KB 左右。
  • StyleX 的目的:開發它是為了有效地大規模管理樣式的複雜性。它解決了眾多開發人員在創建數千個組件時出現的挑戰,這通常會導致 CSS 內的特殊性衝突。透過提供結構化的樣式框架,StyleX 有助於保持樣式過程的一致性和清晰度。
  • 原子類生成:從一開始,StyleX 就一致地產生原子類,接受每個組件具有多個類名的權衡,以提高可維護性並減少樣式衝突。

StyleX 的主要特點:

  1. 原子 CSS 生成:StyleX 採用原子 CSS 生成,這表示它為每個樣式規則建立小型、可重複使用的類別。這種方法不僅可以最大限度地減少最終 CSS 套件中的冗餘,還可以透過減少樣式表的整體大小來提高效能。

  2. CSS 重複資料刪除:透過為每個樣式產生唯一的類別標識符,StyleX 有效地消除了重複的樣式。此重複資料刪除程序可確保每個屬性值對僅渲染一次,進一步有助於實現更精簡的 CSS 輸出。

  3. 「最後應用的樣式總是獲勝!」:StyleX 遵循可預測的樣式規則,其中最後應用的樣式優先。此功能簡化了調試並增強了開發人員的信心,因為它減輕了對樣式規則衝突的擔憂。

  4. 針對 React 進行了最佳化:StyleX 專為 React 應用程式設計,無縫整合到 React 生態系統中。它允許開發人員直接在其元件中定義樣式,從而形成更具凝聚力的開發工作流程。

  5. Flow 和 TypeScript 支援:StyleX 是用「Flow」(由 Meta 創建)編寫的,它還為 TypeScript 提供強大的支持,為樣式和主題啟用類型安全的 API。這種類型安全性增強了程式碼的可靠性和可維護性,使管理複雜的樣式場景變得更加容易。

  6. 靈活的條件樣式:使用 StyleX,開發人員可以依照元件狀態或 props 有條件地套用樣式。這種靈活性允許動態樣式適應使用者互動或應用程式狀態的變化。

  7. 範圍樣式:StyleX 的範圍樣式功能可確保樣式僅套用於其預期的元件。這可以防止大型程式碼庫中經常出現的意外副作用和特異性問題。

  8. 更少的運行時計算:StyleX 通過在編譯時將所有樣式捆綁到靜態 CSS 文件中來最大限度地減少運行時計算。這種優化可以縮短渲染時間並提高效能,尤其是在大型應用程式中。

  9. 更好的程式碼可維護性:透過將樣式與其各自的組件共置並利用原子類,StyleX 提高了程式碼的可維護性。開發人員可以輕鬆理解和修改樣式,而無需篩選大量樣式表。

  10. 最小 CSS 輸出:使用原子 CSS 會導致最小 CSS 輸出,這對效能特別有利。隨著專案規模和複雜性的增加,StyleX 可確保 CSS 捆綁包在不犧牲功能的情況下保持可管理性。

  11. 適用於各種規模的項目:雖然 StyleX 適用於各種規模的項目,但它在大型應用程式中確實表現出色。其架構旨在處理廣泛的樣式需求的複雜性,而不影響效能或可維護性。

讓我們看看它是如何運作的?

本文中的程式碼範例是用 React 寫的,我們將主要使用兩個元件:App.jsx 和 Button.jsx。在新增樣式之前,我們先來看看這些元件的基本結構。

import Button from "./components/Button";

const App = () => {
  return (
    <div>
      <h1>StyleX by Meta</h1>
      <Button text="Get Started" />
    </div>
  );
};

export default App;
// Button.jsx
import PropTypes from "prop-types";

const Button = ({ text }) => {
  return <button>{text}</button>;
};

Button.propTypes = {
  text: PropTypes.string.isRequired,
};

export default Button;

Decoding StyleX: Meta

使用 StyleX 新增樣式

import PropTypes from "prop-types";
import * as stylex from "@stylexjs/stylex";

const styles = stylex.create({
  base: {
    fontSize: 18,
    backgroundColor: "black",
    color: "white",
  },
});

const Button = ({ text }) => {
  return <button {...stylex.props(styles.base)}>{text}</button>;
};

Button.propTypes = {
  text: PropTypes.string.isRequired,
};

export default Button;

要使用這些樣式,我們需要從 styleX 套件中匯入它們,然後使用以物件作為參數的 stylex.create 方法定義樣式。然後我們可以使用 stylex.props 方法將樣式套用到元件。

在此範例中,base 是我們要套用的樣式的名稱。我們在 StyleX 中稱它們為 命名空間。這就是我們的按鈕組件現在的樣子。

Decoding StyleX: Meta

為偽類添加樣式

import PropTypes from "prop-types";
import * as stylex from "@stylexjs/stylex";

const styles = stylex.create({
  base: {
    fontSize: 18,
    backgroundColor: {
      default: "black",
      ":hover": "blue",
    },
    color: "white",
  },
});

const Button = ({ text }) => {
  return <button {...stylex.props(styles.base)}>{text}</button>;
};

Button.propTypes = {
  text: PropTypes.string.isRequired,
};

export default Button;

使用 StyleX,為偽類添加樣式非常簡單。在前面的範例中,backgroundColor 是一個字串。在這裡,我們將其轉換為具有預設值和偽類別的物件。

Decoding StyleX: Meta

使用媒體查詢

import PropTypes from "prop-types";
import * as stylex from "@stylexjs/stylex";

const styles = stylex.create({
  base: {
    fontSize: 18,
    backgroundColor: {
      default: "black",
      ":hover": "blue",
    },
    color: "white",
    width: {
      default: "100px",
      "@media (max-width: 476px)": "100%",
    },
  },
});

const Button = ({ text }) => {
  return <button {...stylex.props(styles.base)}>{text}</button>;
};

Button.propTypes = {
  text: PropTypes.string.isRequired,
};

export default Button;

與其他樣式庫相比,我們在 StyleX 中做的不同的一件事是媒體查詢。在這裡,我們根據需求將媒體查詢應用於每個命名空間。在此範例中,我們將較大螢幕的按鈕寬度定義為 100px,較小螢幕或行動裝置的按鈕寬度定義為 100%。

Decoding StyleX: Meta

讓我們看看如何“最後應用的風格總是獲勝”

讓我們擴展前面的範例,看看如何建立此按鈕的不同變體。

const styles = stylex.create({
  base: {
    fontSize: 18,
    backgroundColor: {
      default: "teal",
      ":hover": "blue",
    },
    color: "white",
    width: {
      default: "100px",
      "@media (max-width: 476px)": "100%",
    },
  },
  highlighted: {
    backgroundColor: "orange",
  },
  danger: {
    backgroundColor: "red",
  },
  primary: {
    backgroundColor: "green",
  },
});

const Button = ({ text, isHighlighted, variant }) => {
  return (
    <button
      {...stylex.props(
        styles.base,
        isHighlighted && styles.highlighted, // conditional styling
        styles[variant]
      )}
    >
      {text}
    </button>
  );
};

Button.propTypes = {
  text: PropTypes.string.isRequired,
  isHighlighted: PropTypes.bool,
  variant: PropTypes.oneOf(["danger", "primary"]),
};

讓我們為 stylex.create 方法添加更多命名空間,並為它們提供不同的背景顏色。此外,我們在 Button 元件中接受了 2 個新的 props。 isHighlighted 是一個布林屬性,我們用它來套用突出顯示的命名空間。變數是我們用來應用主要、危險或突出顯示的命名空間的道具。

// App.jsx
import Button from "./components/Button";

const App = () => {
  return (
    <div>
      <h1>StyleX by Meta</h1>
      <div {...stylex.props(styles.main)}>
        <Button text="Base Button" />
        <Button text="Highlighted Button" isHighlighted />
        <Button text="Danger Button" isHighlighted variant="danger" />
        <Button text="Primary Button" variant="primary" />
      </div>
    </div>
  );
};

export default App;

我們建立了幾個 Button 元件的副本,並傳遞不同的 props。這就是我們的應用程式現在的樣子。

Decoding StyleX: Meta

現在,仔細看看「危險按鈕」。即使我們將 isHighlighted 傳入 true,突出顯示的命名空間也不會套用。最後提到了危險變體,因此將應用它。因此,該按鈕將具有紅色背景顏色。

覆蓋父級的樣式

我們可以直接從 App.jsx 覆寫此 Button 元件的樣式屬性。

import Button from "./components/Button";

const App = () => {
  return (
    <div>
      <h1>StyleX by Meta</h1>
      <Button text="Get Started" />
    </div>
  );
};

export default App;

Decoding StyleX: Meta

在此範例中,覆蓋命名空間目前允許任何屬性。然而,StyleX 使我們能夠限制哪些屬性可以被覆寫。使用 TypeScript 時,此功能變得特別有用。

// Button.jsx
import PropTypes from "prop-types";

const Button = ({ text }) => {
  return <button>{text}</button>;
};

Button.propTypes = {
  text: PropTypes.string.isRequired,
};

export default Button;

此限制可確保只有 backgroundColor 和 color 屬性可以被覆寫。

原子類如何運作(內部)

Decoding StyleX: Meta

如果您向上捲動到前面的範例程式碼,您將看到我們已將margin: "1rem" 樣式新增至3 個不同的命名空間- App.jsx 中的main、Button.jsx 中的反白顯示和主要。當我們使用 Devtools 檢查元素時,我們可以看到不同的元件(主容器、突出顯示的按鈕和主按鈕)附加相同的類別名,並且只有 1 個類別 x42y017 保留 margin: "1rem" 樣式。

這就是 StyleX 透過使用原子類顯著減小其包大小的方式。達到一定閾值後,不再產生新的類別;相反,他們只是重複使用現有的類別。

全域變數和主題

能夠在粒度層級覆蓋樣式真是太棒了!然而,任何給定的設計系統都需要支援設計標記和主題。這就是 StyleX 的用武之地。 StyleX 中主題 API 的設計直接受到 React Context API 的啟發。變數的定義預設值與 React Context 的建立方式類似,並且可以建立主題來為 UI 子樹的這些變數「提供」不同的值。

我們可以透過建立 x.stylex.js 檔案來建立全域樣式。確保遵循此命名約定。在此文件中,我們使用 stylex.defineVars,如下所示。

import PropTypes from "prop-types";
import * as stylex from "@stylexjs/stylex";

const styles = stylex.create({
  base: {
    fontSize: 18,
    backgroundColor: "black",
    color: "white",
  },
});

const Button = ({ text }) => {
  return <button {...stylex.props(styles.base)}>{text}</button>;
};

Button.propTypes = {
  text: PropTypes.string.isRequired,
};

export default Button;

我們指的是使用者首選的主題並將其設定為常數值 - DARK。此外,讓我們使用此顏色變數建立一個新主題。

import PropTypes from "prop-types";
import * as stylex from "@stylexjs/stylex";

const styles = stylex.create({
  base: {
    fontSize: 18,
    backgroundColor: {
      default: "black",
      ":hover": "blue",
    },
    color: "white",
  },
});

const Button = ({ text }) => {
  return <button {...stylex.props(styles.base)}>{text}</button>;
};

Button.propTypes = {
  text: PropTypes.string.isRequired,
};

export default Button;

主題建立後,就可以像 StyleX 中的任何其他樣式一樣使用。

import PropTypes from "prop-types";
import * as stylex from "@stylexjs/stylex";

const styles = stylex.create({
  base: {
    fontSize: 18,
    backgroundColor: {
      default: "black",
      ":hover": "blue",
    },
    color: "white",
    width: {
      default: "100px",
      "@media (max-width: 476px)": "100%",
    },
  },
});

const Button = ({ text }) => {
  return <button {...stylex.props(styles.base)}>{text}</button>;
};

Button.propTypes = {
  text: PropTypes.string.isRequired,
};

export default Button;

這就是我們如何分別在淺色和深色模式下看到與 myCustomTheme 相同的頁面。

Decoding StyleX: Meta

這就是裹?

萬歲!我們已經成功掌握了與 StyleX 合作的要點。感謝您閱讀本文。我希望它能讓您更好地理解什麼是 StyleX、Meta 是如何創建它以及如何使用它。請在評論部分或 Twitter 上分享您的想法/問題。如果您對這個部落格感興趣,如果您能給這篇文章點個讚(用您最喜歡的表情符號?),我將不勝感激。

平安✌

參考

  • 關於我的課程
  • 在這裡觀看我的演講!
  • React India 對我來說怎麼樣?

在 Topmate 上與我聯繫以進行面試準備
Decoding StyleX: Meta

以上是解碼 StyleX:Meta 的尖端造型系統的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn