SVGでボタンを描く

私は現在単一のWebアプリケーションで作業しているので、現在のかなり不器用なインターフェースをよりモダンで美しいものに更新したかったのです。 最も技術的にロードされた部分と同様に、ボタンから開始することにしました。外観を置き換えるだけでなく、押すこととイベント処理の指示を追加することも必要です。 すぐに問題が発生しました:スケーリングを提供する方法? ユーザーは異なるフォント(タイプとサイズの両方)を使用できるため、通常のビットマップイメージを省くことができず、背景イメージはそれらに適合しません。 これらの目的でSVGを使用しようとするのは論理的です。



残念ながら、最終的に、私はシープスキンは努力する価値がないという結論に達しました:このアイデアを実装しようとすると、あまりにも多くの問題が出ました。 それにもかかわらず、私はこの時期が失われたとは考えていません。新しい知識とスキルを身につけました。そして、私の道を歩む人々の生活を楽にするために、コミュニティでそれらを共有したいと思います。 私は2つの記事で苦しみを説明する予定です。1つ目はSVG画像自体の作業、2つ目はボタンとして結果の画像を導入する手法、この場合に発生する問題、およびその解決策または回避策です。 最初の部分を気にする人は、猫をお願いします。



そもそも、SVG領域は私にとってまったく新しいものであり、考えられるすべての機能やあらゆる種類のトリッキーなトリックを完全に探求する機会がなかったことを警告したいと思います。 したがって、「これを行うことは不可能です」などのフレーズがテキストに含まれている場合は、「標準、教科書、またはGoogleでこれを行う方法が見つかりません」からの省略形と見なしてください。 :-)当然、訂正や説明に非常に感謝します。



では、TKに取りかかりましょう。Webページのボタンとして使用できる、スケーラブルな美しい画像が欲しいです。 実験デザインの基礎として、私はサイトから気に入ったボタンを選択しましたOne Day files



ボタンの例



画像を少し整理して、ベクトルの説明を作成しました。境界に沿って、丸みを帯びたエッジのある灰色の長方形があり、内側に2つの線形領域(50%/ 50%)で構成される垂直方向のグラデーションがあります。 結果は、SVGレッスンの最初のクラスの基本的なタスクでした。 ソリューションは次のようになります。

<defs> <linearGradient id="btnGrad" x1="0%" y1="0%" x2="0%" y2="100%"> <stop offset="0%" stop-color="#777777" /> <stop offset="50%" stop-color="#303030" /> <stop offset="100%" stop-color="#1c1c1c" /> </linearGradient> </defs> <rect style="fill: url(#btnGrad); stroke: #7f7f7f; stroke-width: 1px;" x="0px" y="0px" width="100%" height="100%" rx="5px" />
      
      





(以下、スペースを節約するために、XMLヘッダーと<svg>タグの定義を省略します。)



ただし、それほど単純ではありません。 これは次のようなものです。



結果-1



鋭い目を持つ同志たちは、おそらくここで何かが間違っていることをすでに見ているでしょう。 残りの部分については、境界線の色を赤に置き換えて、見やすくなるように画像を増やします。



結果-1a



結果-1a(増加)



第一に、境界線はある種のぼやけた、ぼやけた、予想よりも暗いことが判明しました。 第二に、境界の角の部分は明らかに側面よりも厚いです。 第三に、丸み付けへの移行は滑らかではなく、角張っています。



全体の問題は、ベクトル座標がピクセルの中心ではなく、ピクセル間の「ギャップ」にあることです。 当然、このような線を描くと、その全長に沿って2つの隣接する位置の間で「ぼやけ」、線の「半分」の1つが画像の外側にあり、表示されません。 通常の長方形がある場合は、色をより明るいものに調整して(ぼかしを補正する)、境界線の太さを2ピクセルに設定することで、それを機能として宣言できます。 ただし、この場合、これは問題を解決しません。丸い角がすべてを損ないます。それらは完全に視界内にあるため、トランジションは角張ったままで、丸みのある線の太さは横方向の境界とは対照的に「完全」のままです。 になる方法 座標を半ピクセルずらすことができます。これにより、「ピクセル間」の問題が解決します。 ただし、この場合、幅と高さを正しく設定できなくなります。「100パーセント-1ピクセル」という値を指定することはできません。 95%を設定しても意味がありません。小さなボタンの場合、5%の差は小さすぎ、大きなボタンの場合は大きすぎます。 すべてのサイズをピクセルのみで指定すると、必要なスケーリングモードを提供できなくなります。境界線の太さはすぐに画像サイズに関連付けられ、比例して変化します。 その結果、高さを変更せずに画像を水平に引き伸ばすと(Webページでのボタンの一般的な使用)、側面の境界線は上下よりも太くなり、非常に見苦しくなります。



ここでの主な問題は、SVGでは受け入れられない、画像の固定部分とスケーラブル部分の割合とピクセル座標を組み合わせようとしていることです。 さらに、判明したように、パーセント座標は数字に対してのみ指定できます。 <path>タグは原則的にそれらをサポートしていません(すべての図は単なる<path>の特殊なケースであるという教科書の保証にもかかわらず)。 さて、普通の形状でうまくやってみましょう。transform属性はこれに役立ちます。 トリックは、初期座標を100%に設定し、幅と高さをピクセル単位で固定として示し、結果の形状(画像の外側にある)を画像に戻し、目的のピクセル数にシフトすることです。 たとえば、左下隅に5×10の長方形を描くには、次のコードを使用できます。

 <rect x="0px" y="100%" width="5px" height="10px" transform="translate(0, -10)" />
      
      





残念ながら、このトリックでさえ、単一の<rect>タグで境界線全体を一度に描画するのに役立ちませんが、単純な形状を組み合わせることにより、境界線が移動する領域のマスクを描画してから塗りつぶすことができます。 もちろん、マスクを描画する特定の方法はさまざまですが、私はこの方法でそれを行いました。2つの長方形フレームを半ピクセルずらして、共通の境界長方形の輪郭を描きました。 それから彼は角の部分を切り取り、その場所に円を置き、最後に、これらの円の余分な部分を切り取り、角を丸くするために四分の一だけ残しました。 結果のコードは次のとおりです。

 <mask id="boundRect"> <rect style="fill: none; stroke: #ffffff; stroke-width: 1px;" x="0.5px" y="0.5px" width="100%" height="100%" /> <rect style="fill: none; stroke: #ffffff; stroke-width: 1px;" x="-0.5px" y="-0.5px" width="100%" height="100%" /> <g style="fill: #000000;"> <rect x="0px" y="0px" width="5px" height="5px" transform="translate(0, 0)" /> <rect x="0px" y="100%" width="5px" height="5px" transform="translate(0, -5)" /> <rect x="100%" y="0px" width="5px" height="5px" transform="translate(-5, 0)" /> <rect x="100%" y="100%" width="5px" height="5px" transform="translate(-5, -5)" /> </g> <g style="fill: #ffffff;"> <circle cx="5px" cy="5px" r="5px" transform="translate(0, 0)" /> <circle cx="5px" cy="100%" r="5px" transform="translate(0, -5)" /> <circle cx="100%" cy="5px" r="5px" transform="translate(-5, 0)" /> <circle cx="100%" cy="100%" r="5px" transform="translate(-5, -5)" /> </g> <g style="fill: #000000;"> <circle cx="5px" cy="5px" r="4px" transform="translate(0, 0)" /> <circle cx="5px" cy="100%" r="4px" transform="translate(0, -5)" /> <circle cx="100%" cy="5px" r="4px" transform="translate(-5, 0)" /> <circle cx="100%" cy="100%" r="4px" transform="translate(-5, -5)" /> <rect x="1px" y="5px" width="9px" height="5px" transform="translate(0, 0)" /> <rect x="5px" y="1px" width="5px" height="9px" transform="translate(0, 0)" /> <rect x="1px" y="100%" width="9px" height="5px" transform="translate(0, -10)" /> <rect x="5px" y="100%" width="5px" height="9px" transform="translate(0, -10)" /> <rect x="100%" y="5px" width="9px" height="5px" transform="translate(-10, 0)" /> <rect x="100%" y="1px" width="5px" height="9px" transform="translate(-10, 0)" /> <rect x="100%" y="100%" width="9px" height="5px" transform="translate(-10, -10)" /> <rect x="100%" y="100%" width="5px" height="9px" transform="translate(-10, -10)" /> </g> </mask>
      
      





もちろん、マスクを使用するか、円から必要な四分の一を切り取るために<clipPath>切り抜くことはより論理的ですが、Operaバージョン11未満の組み込み使用ではソーセージがクールになります:最初の描画は正しく実行されますが、別のウィンドウをドラッグすると、イメージの更新は正しく実行されません。 このグリッチに突き当たるよりも、ネストされたマスクを放棄し、通常の長方形で覆う方が簡単であることが判明しました。



実際、ボタンはほとんど準備ができています。 テキストを掛けるだけで残っていますが、ここで問題が発生しました。 まず、それが主要なものです。フォントサイズはどうあるべきですか? この質問に対する簡単な解決策はありませんでした。SVG画像とHTMLページの統合に最も直接関係しているため、この問題の検討は次の記事に延期しますが、ここでは、説明のために、フォントサイズをデフォルトのままにします。 また、テキストを中央揃えにしたかったのですが、そのような単純なタスクでさえ、フォントベースの調整方法がわからない一部のブラウザー(これはFirefoxではありますが、指で指すことはありません)の能力を超えていることが判明したため、今のところは水平方向にのみセンタリングする必要があります。



最後の写真では、マウスをホバーし、スクリプトの助けを借りてボタンを押すときに強調表示を追加し、一部の説明をスタイルに翻訳しました。 これにより、問題は発生せず、すべてがすぐに正常に機能しました。したがって、これらのことの説明でテキストを散らかすことはありません。それらはすべての教科書にあります。 結果のボタンのコードは、 ここで表示できます



どのように見えるかを確認したい場合は、実際のを使用してみてください(もちろん、SVGをサポートするブラウザーが必要です)。



トマトをキャッチする準備ができて、あなたの注意をありがとう。 :-)



UPD: 記事の第2部



All Articles