首頁 >web前端 >css教學 >% CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位

% CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位

Linda Hamilton
Linda Hamilton原創
2025-01-18 06:10:09428瀏覽

這是在 CSS 中取得 32 位元 API 回應資料的直接後續內容

在 CSS 中,將 16 位元回應資料放置在固有寬度和固有高度中,與根本無法取得 API 回應資料(沒有 JavaScript)相比,這是一個巨大的改進...

然而,在我弄清楚這一點後的幾天裡,我的想法偏向一個方向:
如果是 16 位的話會更有趣32 次而不是僅僅兩次。

Gif recording of a harsh terminal app setting several integer values to an array of variables one at a time

將 512 位元打包到 SVG 中以進行滲透

我在睡前冥想,突然想到了另一個靈感 -

「如果圖片文件本身可以為其自己內在大小設定動畫怎麼辦?」

在靈感迸發的想法之後,通常會出現一系列的實現,每一個都閃現出對如何實現它的理解......我只需要弄清楚這樣的圖像類型是否存在。

我抓起手機,搜尋了我所知道的所有動畫圖像格式,看看它們是否有能力。 svgwebpapnggif也許是奇怪的影片格式?我沒找到。

早上,我內心的某個聲音告訴我繼續挖掘 SVG

我嘗試過嵌入 CSS、媒體查詢、使用定義、更多使用定義、深入研究眾多 SVG 動畫文檔、試圖欺騙它們,並閱讀其他想法和動畫相關屬性 - 沒有什麼可以讓我設定高度或寬度。

但是最後一個連結讓我想到......

...viewBox 怎麼樣?我還有其他一些障礙需要解決,但是......那個可以製作動畫嗎?

vvv
就是這樣! !
^^^

整理解空間

現在的問題是,如果你沒有在根svg 元素上設定寬度和高度屬性,然後嘗試使用svg 作為偽元素的內容,它會呈現0px x 0px,因為它是一個向量文檔,不再有內在尺寸。

所以我搜尋並向其中添加了preserveAspectRatio...仍然是0x0...但是然後在我的CSS中,我將寬度固定為10px,並讓viewBox保留的寬高比決定高度(我可以用嵌入SVG 中的動畫)aaand...包含它的html 元素成長到預期高度。

:3

如果只有一幀,這會將我原來的 32 位元切成兩半;因為只有一個維度可以被滲透,而另一個維度是靜態的。

但是!現在,我的第二個維度是時間,第一個維度受時間支配,所以有足夠的資料可供使用。

多麼令人興奮!

我學習了所有關於如何控制 SVG 中的動畫的知識,並編寫了一個伺服器端腳本來產生我的第一個動畫 SVG:

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

(為什麼是php?! - 因為我已經有了一台我已經支付多年費用的服務器,設置為運行php......儘管我已經通過了解JavaScript 和Node 過著美好的生活真的很好,有時查找每個函數、運算符和語法以完成您知道可以在不知道具體細節的情況下可以做的事情是很有趣的。 🎜>

現在讓我們從上一篇文章中分叉我的第一個 % CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位,以查看 CSS 隨著 SVG 的變化而響應和改變大小 --vars:

確認!我們

可以讀取尺寸變化。就像上一篇文章一樣,最終,它將使用視圖時間軸測量技術而不是 tan(atan2()) 技術。

它會耗盡我的 CPU,因此我們希望在洩漏完成後將其從內容中刪除。

從概念上講,如何在程序上滲透一維時間

上面的示範本身並不是很有用。只要它存在,它就會報告高度的副本,但我們需要保存它......如果您不知道並且不能信任該順序,那麼一堆 16 位元值有什麼用呢?

我知道我可以使用 CPU Hack 累積 CSS 中的值,並以數學方式確定哪個 --var 更新傳入的值,而不是只保留其先前的值,因此我不會專門擔心 CSS。一般來說,我們如何隨著時間的推移滲透一維?

哨兵值來救援!

即使我想將資料包本身限制為 16 位,我們使用的測量區域的大小也不必限制為 16 位。所以我們也可以在那裡裝一些哨兵。 css-api-fetch 能夠處理高達 99999 的值,遠高於 65535(16 位元上限)。

那我們需要知道什麼?

我們可能會遇到什麼問題?

如果

資料中的兩個值連續相同,我們需要中斷才能知道這是兩個不同的資料包。我已經決定我們的目標是 512 位,因此我們需要 SVG 動畫最多有 32 個 16 位元資料幀,中間有哨兵幀...

如果 CPU 感覺很重,SVG 動畫可能會完全跳過離散步驟。這意味著我們需要某種方式來始終知道我們正在進行哪一步。因此,我們不是使用單一「資料幀之間」哨兵,而是使用資料索引(像CSS nth-* 選擇器一樣基於1)作為哨兵值,使其成為顯示該索引資料的離散步驟之前的自己的離散步驟。

哨兵指數->資料->哨兵指數->資料...

這讓我們知道它何時循環,可能是當我們到達哨兵 1 時。

但是我們怎麼知道它沒有跳到不同的資料框並且不小心讓我們將它記錄在錯誤的槽中

我們需要讓它循環並繼續直到正確,而了解資料是否正確的最佳方法是校驗和!所以我們需要另一個資料框,以及該值的哨兵。

創建校驗和演算法

我可以使用 css-bin-bits 來異或所有數據,但它相當繁重並且在其他任何地方都不需要 - 讓我們選擇一個在 CSS 中很容易實現的替代方案。

從數學上講,如果您採用 16 位元值,將其除以 256(底數到整數),然後再次採用 16 位元值除以 256,您將得到高位元組和低位元組。將這 8 位元值加在一起,就得到了 9 位。這感覺像是一個合理的校驗和方法,但讓我們回到這一點。

只要最後校驗和是16 位,我們就不必保持在16 位範圍內來計算校驗和,所以讓我們將所有(最多)相加32個值。

我們必須小心因跳幀而導致的錯誤儲存寫入,所以讓我們加入偶數索引值兩次,這樣就有一些相似的順序

16 位元值的總和,32 次,再加上額外的 16 次,約為 22 位元。將每一側的 11 位元除以模,回到先前的想法,然後將它們加在一起,得到 12 位元作為我們的校驗和回應。

似乎是合理的...它並不完全防錯,但SVG 必須跳過幾個步驟來搞亂它,以便現在可能生成相同的校驗和...無論如何,讓我們也發回資料長度並也將其包含在校驗和中,只需將其新增為校驗和的最後一步即可。最大資料長度(我們想要處理的 16 位元值的數量)僅為 32,因此將長度值加到 12 位元並不會讓我們超過 16 位元。耶!

劇透:這我所做的,但CSS 在21 位​​元左右的某個地方變得有損,所以我將其分割並有效地執行相同的演算法,但一次分成較小的塊。伺服器端完全按照描述使用 alg。

從技術上講,根據我們描述的設置,動畫中的順序並不重要,只要每個哨兵告訴您下一幀應該在數據

還有一件事,讓我們將資料長度值放在回應中的第一位,並為其添加一個哨兵(SVG 動畫中的哨兵位於該值之前,與其餘資料一樣)。

這是34 個哨兵。 SVG viewBox 高度不能為 0,CSS 將受益於允許 0 在內部表示沒有數據,所以假設我們有 35 個哨兵,其中 0 故意未使用。

所有資料框現在都嵌入到 SVG 中,並在其值上添加 35 。長度和校驗和資料值也將 35 加到視圖框值中。 SVG 動畫中代表哨兵的 viewBox 高度的值將是 0 到 34(跳過 0),每個值都準確地告訴我們 SVG 動畫中的下一幀代表什麼。

CSS 方面,我們只檢查

原始測量值是否大於 34,它是數據,因此從中減去 35,如果它小於 35,它是哨兵。

A meme picture of Charlie Day from It's Always Sunny in Philadelphia with a crazed look standing in front of a board covered in paper with red lines connecting them hectically

開始用 CSS 滲透 512 位

在我完成 PHP 端詳細產生 SVG 動畫之後,我想到了開始 CSS 進行此滲透過程的具體方法。

這是 PHP 程式碼!
<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

有幾種方法可以在 CSS 中實現此目的,而最近添加的規格可能會提供更多方法。

我的第一種方法在概念上是最簡單的 - 對每條資料使用視圖時間軸並一遍又一遍地執行相同的操作。它確實有效,但我對自己的進展感到不滿,因為它有多糟糕。如果我繼續的話,:root 上將有近 40 個動畫。

所以我去睡覺了。

當我醒來時,我躺在那裡好一會兒,看著窗外微笑著,帶著剛剛醒來或沉思的嗡嗡聲,然後一連串的想法湧入我的腦海。我翻了個身,抓起我的筆記本和最近的筆,從床上坐起來,開始寫下僅用 6 個 CSS 動畫就能竊取它的演算法。

my chicken scratch handwriting on a single piece of lined notebook paper with arrows pointing to a couple of nested boxes detailing the method described below

在紙上解決了;這就是

完全它的實現方式。

我起身,打開電腦,忽略了之前的工作,打開了一個新的% CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位。

我在那裡設定了雞抓痕中指示的 4 個 html 元素,然後在 CSS 面板中填充了與它們對應的 4 個空類選擇器周圍的註釋。現在它不會在 :root 上,但我們可以在裡面放置任何依賴它的東西。

在從紙上複製筆記並在 % CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位 中以更具體的細節編寫註釋之前,沒有添加任何功能。

完成後,我只是閱讀筆記並開始實施他們所說的,一直到最終的工作結果。

(我寫了“20”而不是“35”,因為我要使用 256 位元進行測試)

我將深入探討它是如何運作的。由於視圖時間軸和時間軸範圍,如果您可以想像表面動畫並被吸進“洞”,回到狹窄的頂部,然後再向下流動,則可以將數據設置為以克萊因瓶形狀流入再次越過表面,透過dom 層獲得大小和複雜性,然後透過黑洞循環回到更高的意識(:root)。

主要是垂直循環(而不是主要是水平循環或靜態循環)

使用 CSS 竊取 512 位

我們稍微調整並使其更加清晰的註解:

256 測驗 ->第512章 決賽

我在裡面新增了一個示範節點,這很棒,因為我也可以在演算法執行時顯示內部結構。

但這是最後的註釋,沒有所有的實現和演示噪音。這準確地描述了它是如何工作的。

對於一篇文章來說,在外部嵌入這麼多細節可能不太好,但我將分解每個區塊來展示如何它是如何實現的。

主控制器

此結構的頂部是 4 個時間軸值及其動畫。所以讓我們把它們放進去。

這實現的資料流的關鍵部分是它使我們能夠將嵌套在 DOM 深處的資料提升回主機(時間軸範圍)。它效率不高,因此我們希望限制執行此操作的頻率。每個註冊的屬性及其動畫都可以垂直託管單一資料。資料的值由結構深處某個元素的內聯或區塊視圖位置決定 - 我們稍後會討論該部分。

(請參閱上面先前嵌入的循環範例,以更清晰地了解資料流)

我們在這裡擷取的四條資料是:

--xfl-cpu-phase - 這是一個 0 到 4 之間的數值,表示目前正在執行 CPU Hack 的哪個階段。 (CPU Hack 的單一「幀」是 4 到 5 個 CSS 渲染幀,階段的一個循環「勾選」CPU Hack)我將在本文後面更具體地演示這一點。

--xfl-raw-data - 無論 SVG 處於其動畫週期中,它都託管 SVG 的高度。我們的原始數據。如前所述,如果該值小於 35,則 SVG 動畫的這個離散步驟是哨兵值。如果它大於 34,則 SVG 動畫的這個離散步驟就是我們的 16 位元值 35,它對應於前面的哨兵指示的值。

--xfl-data-type - 這是最新的哨兵值。在遇到下一個標記之前,該值不會變更。從設定 --xfl-raw-data 到設定此值有 1 個 CSS 幀延遲。

--xfl-data-value - 這是從原始值中減去 35 後的目前資料值,如果我們尚未達到序列的這一步,則為 0。從設定 --xfl-data-type 到設定此值有 1 CSS 幀延遲。

我還預先將 svg-animation-current-state-reporter 包裝在一個僅具有功能的條件下,並且僅在該過程不完整時加載動畫 SVG。 (因此,當我們完成時,所有內部結構都會從內存中刪除,並且重型動畫 svg 也會從渲染中刪除)

關鍵影格值從該資料的最大值變成 0。稍後我將解釋為什麼這些值是向後的 - 尋找 Uno Reverse 卡的圖像。

CPU 提取器

接下來我們設定 CPU Hack 的基本樣板

CPU Hack 樣板只是遵循變數名稱模式來設定捕捉和提升動畫。

如果我們有 1 個整數 --xfl\1 我們想要水平循環(隨著時間的推移),我們註冊它並設定捕獲和提升動畫,如下所示:

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

然後完成託管兩個CPU動畫的.cpu-exfiltrator元素的循環分配。我現在只針對其中一個值執行此操作:

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  // add 35 to all the values so we can use 0 to 34 for sentinels. 0 = CSS-side sentinel, 1-32 = data frames, 33 = length, 34 = checksum
  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return ($viewBoxXYWidth . ((string) $index) . '; ' . $viewBoxXYWidth . ((string) ($val + 35)));
  }, $data, range(1, $datalen)); // 1 up to 32 = indicator that next frame is the value(+35) for that index(1-based)

  // no matter how many are in the array, '33' indicates the next frame is data length, which is used in the checksum too
  array_unshift($frames, $viewBoxXYWidth . '33; ' . $viewBoxXYWidth . ((string) ($datalen + 35))); // + 35 b/c data
  // unshift so the length is (hopefully) the first value read and a sense of progress can be reported

  $fullsum = 0;

  for ($x = 0; $x <= ($datalen - 1); $x++) {
    // double the odd ones so there's some semblance of order accounted for
    // the odd ones with 0 based index is the even ones on the CSS side
    $fullsum += ($data[$x] + (($x & 1) * $data[$x]));
  }

  $checksum = floor($fullsum / 2048) + ($fullsum % 2048) + $datalen + 35; // + 35 because it's data

  // no matter how many are in the array, '34' indicates the next frame is checksum
  array_push($frames, $viewBoxXYWidth . '34; ' . $viewBoxXYWidth . $checksum);

  $actualNumItems = count($frames) * 2;

  $dur = $actualNumItems * 0.33; // total seconds

  $keytimeStep = 1 / ($actualNumItems); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $actualNumItems - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

在 Chrome 中,除非兩個動畫同時運行,否則它們不會靜態循環(成為初始值)。這可能是暫停動畫設定數位屬性的最佳化的一個奇妙的副作用。

最後,由於我們使用的是CPU Hack 的新自動版本(您不必像原始hack 中那樣通過:hover 來循環階段),因此我們連接--xfl-cpu-phase var來自之前的(託管在此處的父元素上,因此我們可以使用樣式查詢來回應它)並控制動畫的播放狀態。

我們也輸出 --cpu-next-phase ,稍後將其提升回頂部,並使用其視圖位置和時間軸範圍為 --xfl-cpu-phase 設定下一個值。

我新增了一個額外的階段來保持 CPU Hack 暫停,直到 SVG 動畫測量成功鎖定下一個 --xfl-data-type

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

(就像現在一樣,資料類型仍然始終為0,因此一旦連接了下一階段,這將已經在循環CPU Hack。一旦我們有了資料類型哨兵,它就不會循環,直到我們完成故意用0哨兵清除它)

稍後,我們還將添加上述條件,以防止 CPU 階段 1 在資料全部到位之前啟動。這將確保在鎖定資料類型(哨兵)和鎖定資料值(原始 - 35)之間,我們希望將 CPU Hack 留在捕獲階段。因此,正如亞伯拉罕·希克斯 (Abraham Hicks) 所說,它「已經做好準備」。

我將繼續註冊我們期望 SVG 動畫報告的所有 32 個值以及校驗和和長度。

由於 --xfl\1 到 --xfl\32 的註冊是一個大塊,並且 CPU 動畫也只是樣板,因此我將把所有這些移動到 hack 設定的底部,以便以後忽略。

自動CPU破解

這會將下一個 cpu 階段連接到 --xfl-cpu-phase 值

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  // add 35 to all the values so we can use 0 to 34 for sentinels. 0 = CSS-side sentinel, 1-32 = data frames, 33 = length, 34 = checksum
  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return ($viewBoxXYWidth . ((string) $index) . '; ' . $viewBoxXYWidth . ((string) ($val + 35)));
  }, $data, range(1, $datalen)); // 1 up to 32 = indicator that next frame is the value(+35) for that index(1-based)

  // no matter how many are in the array, '33' indicates the next frame is data length, which is used in the checksum too
  array_unshift($frames, $viewBoxXYWidth . '33; ' . $viewBoxXYWidth . ((string) ($datalen + 35))); // + 35 b/c data
  // unshift so the length is (hopefully) the first value read and a sense of progress can be reported

  $fullsum = 0;

  for ($x = 0; $x <= ($datalen - 1); $x++) {
    // double the odd ones so there's some semblance of order accounted for
    // the odd ones with 0 based index is the even ones on the CSS side
    $fullsum += ($data[$x] + (($x & 1) * $data[$x]));
  }

  $checksum = floor($fullsum / 2048) + ($fullsum % 2048) + $datalen + 35; // + 35 because it's data

  // no matter how many are in the array, '34' indicates the next frame is checksum
  array_push($frames, $viewBoxXYWidth . '34; ' . $viewBoxXYWidth . $checksum);

  $actualNumItems = count($frames) * 2;

  $dur = $actualNumItems * 0.33; // total seconds

  $keytimeStep = 1 / ($actualNumItems); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $actualNumItems - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

這裡有一些 CSS 樣板,可以使元素成為滾動容器並將其移出螢幕。重要的部分是:

視圖時間軸:--xfl-cpu-phase inline;

它表示這個偽元素的右邊緣落在其100px 寬的父元素中的位置,將其作為從左側到我們從0 移動到4 的動畫的「進度」連接起來...所以25px 是完成的25%,當25% 在0 到4 之間時映射為1。

picture of two 'reverse' cards from Uno 圖片源自Google搜尋並指向 Twitter

從技術上講,動畫是 4 比 0,並且從技術上講,當視圖向右移動時,它是從偽的右邊緣開始測量的。因此,25px 寬的偽值距離其 100px 寬的滾動父級右側為 75%,當 75% 介於 4 和 0 之間時,對應到值 1。

如果你不認知地處理反向逆向數學,只是接受最終結果是一個簡單的進度0 到4,那麼會更容易理解,因為動畫中的最大值是4(再次忽略動畫開始 4)。

我們也要寫就緒狀態,將 CPU 保持在階段 0,直到資料準備好。註解位於我們示範的第 64 行:

資料準備好 = 資料類型 > 0 && 原始幀資料 - 35 === 資料值

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

等等,CSS 中的 === ?

這些現在已經非常過時了,今天我會以不同的方式做它們,在clamp()成為基線之前編寫,但是當我需要它們時,我總是打開這個舊的codepen來無意識地複製粘貼數字比較器。更新這些並解釋它們將是一篇很好的文章,但同時您可以閱讀:https://codepen.io/propjockey/pen/YzZMNaz

讀取 SVG 動畫

這最初非常類似於 CPU Exfiltrator 部分,因為它是相同的技術,測量資料並將資料從 DOM 向上移動到其託管位置(範圍)。

我們將測量並報告我們最初設定的基本元素的最後 3 個值。

在 ::before 之前,我們將渲染 SVG 並使用區塊視圖位置設定 --xfl-raw-data,該位置是動畫 SVG 高度的測量值。 (記住,我們將寬度固定為 10px)

在 ::after 上,我們將設定 --xfl-data-type 內嵌(標記值 0 到 34)和 --xfl-data-value 區塊(16 位元值)。

父級需要足夠寬才能渲染 SVG(至少 10 像素)並準確提供哨兵值的測量值(0 到 34)。

父級也需要夠高才能測量 16 位元值 ( 35)。由於我們在第一步中設定了 100k 的最大值,因此即使它比我們需要的大 30% 左右,我們也只會使用它。

並將其移出螢幕到頂部和左側,這樣就不會導致捲軸。

因此,

.svg-animation-current-state-reporter

得到

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  // add 35 to all the values so we can use 0 to 34 for sentinels. 0 = CSS-side sentinel, 1-32 = data frames, 33 = length, 34 = checksum
  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return ($viewBoxXYWidth . ((string) $index) . '; ' . $viewBoxXYWidth . ((string) ($val + 35)));
  }, $data, range(1, $datalen)); // 1 up to 32 = indicator that next frame is the value(+35) for that index(1-based)

  // no matter how many are in the array, '33' indicates the next frame is data length, which is used in the checksum too
  array_unshift($frames, $viewBoxXYWidth . '33; ' . $viewBoxXYWidth . ((string) ($datalen + 35))); // + 35 b/c data
  // unshift so the length is (hopefully) the first value read and a sense of progress can be reported

  $fullsum = 0;

  for ($x = 0; $x <= ($datalen - 1); $x++) {
    // double the odd ones so there's some semblance of order accounted for
    // the odd ones with 0 based index is the even ones on the CSS side
    $fullsum += ($data[$x] + (($x & 1) * $data[$x]));
  }

  $checksum = floor($fullsum / 2048) + ($fullsum % 2048) + $datalen + 35; // + 35 because it's data

  // no matter how many are in the array, '34' indicates the next frame is checksum
  array_push($frames, $viewBoxXYWidth . '34; ' . $viewBoxXYWidth . $checksum);

  $actualNumItems = count($frames) * 2;

  $dur = $actualNumItems * 0.33; // total seconds

  $keytimeStep = 1 / ($actualNumItems); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $actualNumItems - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

之前變成

@keyframes capture {
  0%, 100% {
    --xfl\1-captured: var(--xfl\1);
  }
}

@keyframes hoist {
  0%, 100% {
    --xfl\1-hoist: var(--xfl\1-captured, 0);
  }
}

和::取得後

  --xfl\1: calc(
    var(--xfl\1-hoist, 0) + 1
  );

本質上,這些後值的儲存媒體是 1px 正方形偽相對於其父滾動容器的視圖位置。我們在左側和頂部的計算中減去 1px,因為偽值本身是 1x1,我們希望它在對應值為 0 時報告 0。

這與之前所做的非常相似。

我們如何計算這些值應該有幾個複雜之處,如註釋所示:

  @container style(--xfl-cpu-phase: 4) {
    animation-play-state: paused, paused;
    --cpu-next-phase: calc(
      min(1, var(--xfl-data-type)) * 4
    );
  }

理解如何解決這個問題的關鍵是任何比較器值都設定為 0 或 1。若為真則為 1,若為假則為 0。然後將其乘以某個值。如果為 false,則結果保持為 0,否則變為任何值。

Ana Tudor 在這裡深入探討了這個想法的運作方式

然後,如果我們進行兩次比較,對第二個值進行不同或相反的比較,並將它們相加(確保最多一個比較器為1),那麼其中兩個相加只是說“else如果」。

如果還沒準備好 * 使用舊值,否則
如果準備好了 * 使用這個新值

這就是我們在報告類型後在 SVG 動畫離散步驟的持續時間內保持哨兵值的方式。

實現它的 CSS 程式碼從第 191 行開始,就在我們放在底部的 --xfl\... 屬性註冊的大塊上方
@property --xfl\1 { 語法:"";初始值:0;繼承:真實; }
...
並且它包含附加註釋:

設定特定的 CSS --var 值(尋址分配)

我們剛剛接觸的邏輯與我們用於所有 --xfl\1, 2, 32 值的概念完全相同。

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

您讀取 --xfl-set\1 就好像 --xfl-data-type 等於 1 使用 --xfl-data-is-ready 並隱含 else 0

--xfl-data-is-ready 是早期建立的,作為將我們保持在第 0 階段的標誌,直到需要翻轉到第 1 階段。

這表示我們的條件是 && 邏輯。兩個標誌都必須為 1 才能通過。

然後你繼續讀取--xfl\1 就好像--xfl-set\1 使用--xfl-data-value (目前的SVG 動畫值),否則如果不是--xfl-set\1 使用- - xfl\1-hoist(CPU hack 為--xfl1 保留的先前值)

這是高度重複的內容,幾乎描述了此次滲透的其餘全部內容。

最後的步驟是運行基本的calc() 和mod() 數學來建立前面所述的校驗和,然後將計算出的校驗和=== 嵌入到SVG 動畫中的校驗和添加到CPU Hack 中,以便我們知道它何時完全的。一切都一樣。

所以現在是時候了。 :)

演示:CSS 動畫 SVG 滲透駭客

因為我想向這個駭客的每個部分展示每個元素一個值,所以這個演示非常繁重。超過 2000 行 HTML 和超過 400 行 CSS。另外,我使用 css-bin-bits 將每個暫存器轉換為二進位等

(點擊 codepen 框架右下角的重新運行即可即時查看它發生的情況!)

沒有 JavaScript!


打開聯絡方式?

如果您認為這很簡潔並希望了解更多信息,請聯繫我們!總是很樂意回答問題。

% CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位 % CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位 DEV Blog % CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位 % CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位
% CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位 % CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位 DEV Blog % CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位 % CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位

?@JaneOri.% CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位

? @Jane0ri

以上是% CSS:取得並竊取嵌入動畫 SVG 中的伺服器產生資料位的詳細內容。更多資訊請關注PHP中文網其他相關文章!

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