20210503のCSSに関する記事は9件です。

【初心者でもわかる】CSSで鏡文字にする方法

どうも7noteです。鏡文字の作り方を解説 CSSで鏡文字を作る方法を解説します。 文字を反転させれば鏡文字になるので、反転させるためにtransformを使います。 transformの中でも2つの方法で反転を再現することができます。 鏡文字の作り方 ・scaleX()を使った方法 style.css span.mirror { transform: scaleX(-1); display: inline-block; } ・rotateY()を使った方法 style.css span.mirror { transform: rotateY(180deg); display: inline-block; } 解説 ※インライン要素には効かないので注意! 左右に反転させるにはscaleもしくはrotateを使います。 scaleは本来大きさを変更するものですが、値がマイナスになると反転するので等倍のマイナス値を指定することで反転ができます。 rotateは回転をさせるときに使います。y軸(縦)を中心に回転させ、文字を反転させます。 まとめ 2つの方法を紹介しました。 どちらの方法でも簡単なので、好きな方でいいかなと思います。 おそまつ! ~ Qiitaで毎日投稿中!! ~ 【初心者向け】WEB制作のちょいテク詰め合わせ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

カルーセル(HTML,CSS,jQueryで作成)

webページ作成でよく使用するカルーセルをコピペで作成できるようにコードをここにまとめます。 完成イメージ フォルダ構成 フォルダ構成は下のようにしています。 root/  ├ index.html  ├ styles.css  ├ main.js  └ img    ├ carousel1.jpg    ├ carousel2.jpg    └ carousel3.jpg 下のHTML、CSS、JavaScriptのコードをそのままコピペし、画像のURLを変えればそのまま使えます。 コード HTML HTML <!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!--CSSの読み込み--> <link rel="stylesheet" href="./styles.css"> </head>  <body> <div class="carousel">   <!--写真表示部分--> <ul class="carousel-area"> <li class="carousel-list"> <img class="carousel-img" src="img/carousel1.jpg" alt="carousel1"> </li> <li class="carousel-list"> <img class="carousel-img" src="img/carousel2.jpg" alt="carousel2"> </li> <li class="carousel-list"> <img class="carousel-img" src="img/carousel3.jpg" alt="carousel3"> </li> </ul>   <!--「次へ」「前へ」移動する矢印--> <div class="arrow-wrap"> <div class="arrow-left"> <button class="arrow-btn js-btn-back" type="button"></button> </div> <div class="arrow-right"> <button class="arrow-btn js-btn-next" type="button"></button> </div> </div>  <!--ページネーション--> <div class="pagination"> <span class="pagination-circle target"></span> <span class="pagination-circle"></span> <span class="pagination-circle"></span> </div> </div> <!--jQueryの読み込み--> <script src="https://code.jquery.com/jquery-2.2.0.min.js" type="text/javascript"></script> <!--javascriptファイルの読み込み--> <script src="./main.js" type="text/javascript"></script> <body> </html> CSS CSS * { margin: 0; padding: 0; -webkit-box-sizing: border-box; box-sizing: border-box; list-style: none; } body { overflow: hidden; } button { cursor: pointer; -webkit-appearance: none; -moz-appearance: none; vertical-align: middle; color: inherit; font: inherit; border: 0; background: transparent; padding: 0; margin: 0; outline: none; border-radius: 0; } .carousel { width: 600px; height: calc(600px * 0.5625); margin: 0 auto; position: relative; overflow: hidden; } .carousel .carousel-area { height: 100%; display: -webkit-box; display: -ms-flexbox; display: flex; position: absolute; } .carousel .carousel-area .carousel-list { width: 600px; height: calc(600px * 0.5625); margin-right: 30px; background-size: cover; background-position: center; background-repeat: no-repeat; } .carousel .carousel-area .carousel-list:nth-child(1) { background-image: url(./img/carousel1.jpg); } .carousel .carousel-area .carousel-list:nth-child(2) { background-image: url(./img/carousel2.jpg); } .carousel .carousel-area .carousel-list:nth-child(3) { background-image: url(./img/carousel3.jpg); } .carousel .carousel-area .carousel-list .carousel-img { width: 1px; height: 1px; clip: rect(1px, 1px, 1px, 1px); -webkit-clip-path: inset(50%); clip-path: inset(50%); margin: -1px; padding: 0; overflow: hidden; position: absolute; } .carousel .arrow-wrap { width: 96%; height: 100%; margin: 0 auto; position: absolute; top: 0; left: 2%; display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-pack: justify; -ms-flex-pack: justify; justify-content: space-between; -webkit-box-align: center; -ms-flex-align: center; align-items: center; } .carousel .arrow-wrap .arrow-btn { width: 48px; height: 48px; background-color: rgba(113, 135, 245, 0.8); border-radius: 50%; -webkit-transition: .2s; transition: .2s; } .carousel .arrow-wrap .arrow-btn:focus { -webkit-box-shadow: 0px 1px 10px -2px rgba(0, 0, 0, 0.8); box-shadow: 0px 1px 10px -2px rgba(0, 0, 0, 0.8); } .carousel .arrow-wrap .arrow-btn:hover { background-color: #334fd8; -webkit-box-shadow: 0px 1px 10px -2px rgba(0, 0, 0, 0.8); box-shadow: 0px 1px 10px -2px rgba(0, 0, 0, 0.8); } .carousel .arrow-wrap .arrow-left { position: relative; } .carousel .arrow-wrap .arrow-left button:before { content: ""; width: 10px; height: 10px; border-top: 2px solid #fefefe; border-left: 2px solid #fefefe; position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-30%, -50%) rotate(-45deg); transform: translate(-30%, -50%) rotate(-45deg); } .carousel .arrow-wrap .arrow-right { position: relative; } .carousel .arrow-wrap .arrow-right button:before { content: ""; width: 10px; height: 10px; border-top: 2px solid #fefefe; border-left: 2px solid #fefefe; position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-70%, -50%) rotate(135deg); transform: translate(-70%, -50%) rotate(135deg); } .carousel .pagination { width: 16%; margin: 5% auto 0; position: absolute; bottom: 3%; left: 42%; display: -webkit-box; display: -ms-flexbox; display: flex; -ms-flex-pack: distribute; justify-content: space-around; } .carousel .pagination .pagination-circle { width: 10px; height: 10px; border: 1px solid #333; border-radius: 50%; background-color: rgba(10, 10, 10, 0.5); } .carousel .pagination .pagination-circle.target { background-color: rgba(10, 10, 100, 0.8); } @media screen and (max-width: 600px) { .carousel { width: 300px; height: calc(300px * 0.5625); } .carousel .carousel-area .carousel-list { width: 300px; height: calc(300px * 0.5625); margin-right: 0; } } JavaScript JavaScript $(function(){ // スライドリストの合計幅を計算⇒CSSでエリアに代入 let width = $('.carousel-list').outerWidth(true); //.carouse-listの1枚分の幅 let length = $('.carousel-list').length; //.carousel-listの数 let slideArea = width * length; //レール全体幅=スライド1枚の幅 × スライドの合計数 $('.carousel-area').css('width', slideArea); //カルーセルレールに計算した合計幅を指定 //スライド現在値と最終スライド let slideCurrent = 0; //スライドの現在値(1枚目のスライド番号としての意味も含む) let lastCurrent = $('.carousel-list').length - 1; //スライドの合計数=最後のスライド番号 //スライドの切り替わりを「changeslide」として定義 function changeslide(){ $('.carousel-area').stop().animate({ //stopメソッドを入れることでアニメーション1回毎に止める left: slideCurrent * -width //代入されたスライド数 × リスト1枚分の幅を左に動かす }); //ページネーションの変数を定義(=スライド現在値が必要) let pagiNation = slideCurrent + 1; //nth-of-typeで指定するため0に+1をする $('.pagination-circle').removeClass('target'); //targetクラスを削除 $(".pagination-circle:nth-of-type(" + pagiNation + ")").addClass('target') //現在のボタンにtargetクラスを追加 }; //-----一定時間毎に処理実行する関数「startTimer」を定義 let Timer; function startTimer(){ Timer = setInterval(function(){ if (slideCurrent === lastCurrent){ slideCurrent = 0; changeslide(); }else{ slideCurrent++; changeslide(); }; }, 3000); }; function stopTimer(){ clearInterval(Timer); //crearInterval:setIntervalで設定したタイマーを取り消す }; startTimer(); //-----------ボタンクリック時の「changeslide」関数を呼び出し---------------- //NEXTボタン $('.js-btn-next').click(function(){ stopTimer(); startTimer(); if (slideCurrent === lastCurrent){ //現在のスライドが最終スライドの場合 slideCurrent = 0; changeslide(); //スライド初期値の値を代入して関数実行(初めのスライドに戻す) }else{ slideCurrent++; changeslide(); //そうでなければスライド番号を増やして(次のスライドに切り替え)関数実行 }; }); //BACKボタン $('.js-btn-back').click(function(){ stopTimer(); startTimer(); if (slideCurrent === 0){ //現在のスライドが初めのスライドの場合 slideCurrent = lastCurrent; changeslide(); //最後のスライド番号を代入して関数実行(最後のスライドに移動) }else{ slideCurrent--; changeslide(); //そうでなければスライド番号を減らして(前のスライドに切り替え)関数実行 }; }); }) 蛇足:CSS(SCSSバージョン) ※下のコードは不要です 下のコードは不要ですが、上のCSSコードは下のSCSSコードをコンパイルしたものですので、一応このコードもこちらに記載しておきたいと思います。 CSS *{ margin: 0; padding: 0; box-sizing: border-box; list-style: none; } body{ overflow: hidden; } button{ cursor: pointer; -webkit-appearance: none; -moz-appearance: none; vertical-align: middle; color: inherit; font: inherit; border: 0; background: transparent; padding: 0; margin: 0; outline: none; border-radius: 0; } .carousel{ width: 600px; height: calc(600px * 0.5625); margin: 0 auto; position: relative; overflow: hidden; .carousel-area{ // width: 3150px; height: 100%; display: flex; position: absolute; .carousel-list{ width: 600px; height: calc(600px * 0.5625); margin-right: 30px; background-size: cover; background-position: center; background-repeat: no-repeat; &:nth-child(1){background-image: url(./img/carousel1.jpg)}; &:nth-child(2){background-image: url(./img/carousel2.jpg)}; &:nth-child(3){background-image: url(./img/carousel3.jpg)}; .carousel-img{ width: 1px; height: 1px; clip: rect(1px, 1px, 1px, 1px); -webkit-clip-path: inset(50%); clip-path: inset(50%); margin: -1px; padding: 0; overflow: hidden; position: absolute; } } } .arrow-wrap{ width: 96%; height: 100%; margin: 0 auto; position: absolute; top: 0; left: 2%; display: flex; justify-content: space-between; align-items: center; .arrow-btn{ width: 48px; height: 48px; background-color: rgba(113, 135, 245, 0.8); border-radius: 50%; transition: .2s; &:focus{ box-shadow: 0px 1px 10px -2px rgba(0, 0, 0, 0.8); } &:hover{ background-color: rgb(51, 79, 216); box-shadow: 0px 1px 10px -2px rgba(0, 0, 0, 0.8); } } .arrow-left{ position: relative; button:before{ content: ""; width: 10px; height: 10px; // cursor: pointer; border-top: 2px solid #fefefe; border-left: 2px solid #fefefe; position: absolute; top: 50%; left: 50%; transform: translate(-30%, -50%)rotate(-45deg); } } .arrow-right{ position: relative; button:before{ content: ""; width: 10px; height: 10px; border-top: 2px solid #fefefe; border-left: 2px solid #fefefe; position: absolute; top: 50%; left: 50%; transform: translate(-70%, -50%)rotate(135deg); } } } .pagination{ width: 16%; margin: 5% auto 0; position: absolute; bottom: 3%; left: 42%; display: flex; justify-content: space-around; .pagination-circle{ width: 10px; height: 10px; border: 1px solid #333; border-radius: 50%; background-color: rgba(10, 10, 10, 0.5); &.target{ // background-color: rgba(10, 10, 10, 0.8); background-color: rgba(10, 10, 100, 0.8); } } } } @media screen and (max-width: 600px){ .carousel{ width: 300px; height: calc(300px * 0.5625); .carousel-area{ // width: 1500px; .carousel-list{ width: 300px; height: calc(300px * 0.5625); margin-right: 0; } } } } 参考サイト
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

a[target="_blank"]::after で付加した画像の位置がおかしい時の対処法

焦った話 いつも通り何も考えずに a[target="_blank"]に外部リンクですよー、という意味の画像をつけて確認..... ※わかりやすいように、aとa::afterそれぞれに色を薄くつけてあります。 謎の空白が空いているではありませんか。しかも、この画像、後続の文にがっつり被ってしまいます。 仕方ない、教えてgoogle先生!ざっと調べました。出てきません。私、焦りました。 原因 デベロッパーツールで一つずつ確認し定期ました。すると、思いもよらないやつが原因でした。そいつは、text-indentだったのです。 HTML <style> p { text-indent: 1em; } </style> <p> <a href="https://google.com" target="_blank">Google</a> </p> 以上のように、pにtext-indentを適用して、 pの子要素にaを配置していました。その影響で、aにもtext-indentが継承されてしまい、謎の空白が空いてしまったのですね。 解決 ということで、aのtext-indentを無効にしてあげればよさそうですね! HTML <style> p { text-indent: 1em; } a { text-indent: 0; } </style> <p> <a href="https://google.com" target="_blank">Google</a> </p> 意図した通りになりました! おわりに text-indentは継承しないで欲しいですね。気をつけましょう!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptでテキスト入力チェック方法

JavaScriptでテキスト入力チェック方法です。 今回はテストプログラムでテストしています。 <!DOCTYPE html> <html lang="ja"> <style> body { padding:50px; background-color: greenyellow; } body #title { color:red; font-size : 50px; } body #name { width:200px; } body #mail { width:400px; } body #button1 { background-color: blue; } </style> <head> <meta charset="utf-8"> <title>sample</title> </head> <body> <h1 id = "title">送信フォーム</h1> <form action = "index4.html" method="POST"> Name:<input type="text" id="name"><br> Mail:<input type="email" id="email"><br> Detail:<textarea id="detail" value="detail" cols="50" rows="3" maxlength="150"></textarea></br> year:<select id = "year"> <option value="2021" id="2021">2021年</option> <option value="2022" id="2022">2022年</option> <option value="2023" id="2023">2022年</option> </select> month:<select id = "month"> <option value="1" id="1">1月</option> <option value="2" id="2">2月</option> <option value="3" id="3">3月</option> <option value="4" id="4">4月</option> <option value="5" id="5">5月</option> <option value="6" id="6">6月</option> <option value="7" id="7">7月</option> <option value="8" id="8">8月</option> <option value="9" id="9">9月</option> <option value="10" id="10">10月</option> <option value="11" id="11">11月</option> <option value="12" id="12">12月</option> </select> <input type="button" id="button1" value="送信" onclick="func1()"> </form> <div id="div1"></div> <script language="javascript" type="text/javascript"> //変数の定義 const name = document.getElementById('name'); const mail = document.getElementById('email'); const detail = document.getElementById('detail'); const button1 = document.getElementById('button1'); //入力チェック処理 const func1 = () => { if((name.value.length == 0 ) && (mail.value.length == 0 ) && (detail.value.length == 0 )){ alert('名前、メールアドレス、詳細が入力されていません。'); } else if ((name.value.length == 0 ) && (mail.value.length == 0 )){ alert('名前、メールアドレスが入力されていません。'); } else if ((mail.value.length == 0 ) && (detail.value.length == 0 )){ alert('メールアドレス、詳細が入力されていません。'); } else if ((name.value.length == 0 ) && (detail.value.length == 0 )){ alert('名前、詳細が入力されていません。'); } else if (name.value.length == 0){ alert('名前が入力されていません。'); } else if (mail.value.length ==0){ alert('メールアドレスが入力されていません。'); } else if (detail.value.length ==0){ alert('詳細が入力されていません。'); } else { if (window.confirm('送信してもよろしいですか?')) { div1.innerText = `Name:${name.value}、Mail:${mail.value}、Detail:${detail.value}、year:${year.value}、month:${month.value}`; } } } </script> </body> </html> length=0の部分でテキストに文字が入っていない場合はアラートメッセージで確認を促すようにしています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

transitionプロパティを理解するために基礎のbuttonを作ってみた

transitionを使ってbuttonにアニメーションをつけてみる 完成版 本当は、アニメーションも付いた画像を掲載したかったが、方法が解らなかったので画像のみ掲載しました。 掲載方法教えてあげてもいいぜ!という心お優しい方ご連絡お待ちしております 目標:transitionの基礎を理解するため テキストエディターはVSCode. ↓下記の方のtransitionの説明を参考にしました @7968様 とても解りやすかったです!!     今回はcodePenで書いてみました♪ ※head部分は省略 See the Pen qBReXEr by トモゑ☛Web作成の37? (@swan2pink) on CodePen. 詳しくcodeを書いてみます .button { cursor: pointer; outline: none; font-size: 30px; width: 200px; height: 100px; background: pink; color: white; border-radius: 10px/10px; box-shadow: 10px 10px 10px #706b6b; transition-property: transform, background, box-shadow, color; ※ transition-duration: 2s; ※ } .button:hover { ※ box-shadow: 3px 3px 3px #8a7070; transform: scale(.5); background: red; color: #8a7070; } transitionは『変化前』 と 『変化後』のcodeの両方を書いてあげます 『変化前』 と 『変化後』の中間を補完する役割をもっています transition-property は、変化が摘要されるcssのプロパティを指定します。 今回だと、 transform, background, box-shadow, color です。 transition-duration: 2s; で、変化が始まって終わるまでの時間を指定してます 『変化後』にどうするかは .button:hoverで指示してます。 ちなみに、transform: scale(.5); は、大きさを変形させるプロパティで、大きさ0.5倍にしています。 大きくしたい場合は scale(2)とかに変更すれば良いと思います! まとめ 今回は、transitionの基本について書いてみました。 引き続き応用にもチャレンジしていきたいと思います 今回は以上です! ありがとうございます
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vuforia Studio CSS備忘録:ボタンウィジェットのスタイルを変更する

はじめに Vuforia Studioでは、よく使うウィジェットに、ボタンウィジェットがある。そのボタンウィジェットのスタイルの変更例を備忘録としておく。 前提 Vuforia Studioで、ARコンテンツを独力で作成できる人が対象。 ボタンを配置する ボタンウィジェットをドラッグ&ドロップで 2Dキャンパスの中央パネルに配置する。スタイル確認用に2つ配置しておく。 すべてのボタンのスタイルを一括変更する ボタンウィジェットのスタイルは、button クラスに設定すると一括変更できる。 色を変更する 画面左の「アプリケーション」をクリックしてスタイル編集を開き、以下のコードを追加する。 // ボタンウィジェット全体へのスタイル設定 .button { border-color: navy; // 枠線色 background: royalblue; // 背景色 color: white; // 文字色 margin: 1px; // 枠の外の余白 } プロジェクトを保存すると、表示に反映され、下図のようになった。一括で変更されている。 個々のボタンのスタイルを変更する button クラスとしていた設定を、button-1 クラスに変更する。 // ボタンウィジェットのスタイル設定 .button-1 { border-color: navy; // 枠線色 background: royalblue; // 背景色 color: white; // 文字色 margin: 1px; // 枠の外の余白 } そして、ボタンウィジェット(ID: bottun-2)のクラスに、「button-1」を入力する。保存して表示に反映すると、以下のようになった。 ボタンの高さを変更する height を指定してみる。まずは大きくしてみる。 // ボタンウィジェットのスタイル設定 .button-1 { border-color: navy; // 枠線色 background: royalblue; // 背景色 color: white; // 文字色 margin: 1px; // 枠の外の余白 height: 100px; // ボタンの高さ } 大きくなった。 この結果で比較すると、左のボタンのデフォルトの高さは、100pxの半分近くのようだ。そこで、デフォルトの高さよりも小さくなるように、height: 25px; と小さくしてみる。 ところが、デフォルトよりも高さは小さくならない。 これは、min-height: 47px; と、line-height: 42px; という設定があるからのようだ。ボタンが小さくなると押しにくくなることを考慮して、これらの設定があるものと思われる。ただ、例えばスマホ画面やウェアラブルデバイス画面のように画面サイズがそれほど大きくない場合は、高さをさらに小さくしたい場合がある。そこで、高さを小さくする設定を試す。 // ボタンウィジェットのスタイル設定 .button-1 { border-color: navy; // 枠線色 background: royalblue; // 背景色 color: white; // 文字色 margin: 1px; // 枠の外の余白 height: 25px; // ボタンの高さ min-height: 25px; // ボタンの高さ最小値(デフォルトは 47px) line-height: 23px; // 文字の行の高さ(デフォルトは 42px) } おぉ、ボタンの高さが小さくなった! ボタンの横幅を変更する(ボタン上の文字を基準に) width: 100px; を追加してみる。横幅が大きくなった。 次に、横幅を小さくするにあたりボタン表示をよく見てみると、枠内で文字の左右に余白がそこそこある。これは、paddingによる文字の左右余白 12px の設定があるからのようだ。width: 100px; を削除して、 padding: 0 1px; を追加してみる(左の 0 は文字の上と下の分、右の 1px は文字の左と右の分)。「ボタンB」の4文字が窮屈だが表示された小さいボタンになった。 今度は、ボタンウィジェットのテキストの「ボタンB」を「B」だけにしてみる。文字の左右にまた余白が現れた。 これは、 min-width: 52px; の設定があるためのようだ。min-widh: 25px; を追加してみる。 // ボタンウィジェットのスタイル設定 .button-1 { border-color: navy; // 枠線色 background: royalblue; // 背景色 margin: 1px; // 枠の外の余白 color: white; // 文字色 height: 25px; // ボタンの高さ min-height: 25px; // ボタンの高さ最小値、デフォルトは 47px) line-height: 23px; // 文字の行の高さ(デフォルトは 42px) padding: 0 1px; // 枠内余白(デフォルトは、上下 0、左右 12px) min-width: 25px; // ボタンの横幅最小値、デフォルトは 52px) } これで、縦 25px、横 25px のボタンになった。 この小ささで実用的か? は実際の使用時の検討に任せるとして、ともかく、ボタン上の文字の周囲の余白をなるべく小さくするボタンにすることが可能であることはわかった。 ボタンの横幅を変更する(配置先レイアウトに応じた横幅にする) 今度は、ボタンの横幅を、配置先のレイアウトの横幅に応じた自動設定にする。そのようなスタイル設定が Vuforia Studio には用意されている。 各ボタンを選択して、画面右のクラスに、「button-block」を追加する。 編集画面上ではこの設定は反映されていないが、プレビューを見ると、配置先の中央パネルの幅に応じたボタン横幅になっている。スタイルに width 設定があっても、それよりもこちらの自動設定が優先されるようだ。 文字のフォントスタイルを変更する font-size: 24px; // 文字サイズ font-weight: bold; // 文字の太さ などで、デフォルトのフォントサイズ 16px ではない他のフォントスタイルに変更できる。尚、これらを変更すると、height、min-height、line-height、width, min-width, padding、などと大きさの整合確認が必要な場合がある。 また、font-family でフォントの指定もできるが、プロジェクトを実際に実行するデバイスがそのフォントを利用できるかに依存する点に注意が必要と思われる。 ボタンとフォントの大きさを簡単に変更する Vuforia Studio では、button-small と、button-large の2つのクラスが用意されている。 ボタンB のクラスに button-small を入力してみる。フォントサイズは 12px とのこと。 ボタンB のクラスに button-large を入力してみる。フォントサイズは 20px とのこと。 尚、フォントだけでなく、幅と高さも相応に変更される。 ボタンの配色を簡単に変更する Vuforia Studio では、ボタンの配色例が用意されている。 上図の上から順に、ボタンのクラス欄に「button button-dark」「button button-positive」「button button-balanced」「button button-assertive」を入力している。何を用意してあるかは、画面左上の「テーマ」をクリックして表示し確認できる。 配色を簡単に変更する+フォントサイズを変更する 例えば、button-balanced で背景色を緑にしつつ、フォントサイズを変える場合、ボタンのクラスに、button button-balanced button-large と入力することで組合せての設定ができる。 button-largeだと、ボタンサイズも大きくなってしまう。フォントサイズだけ大きくしたいのであれば、フォントサイズを指定するクラス名(下記の例では font-20)を、button-large の代わりに入力すればよい。 // 文字サイズ設定 .font-20 { font-size: 20px; // 文字サイズ } 配色を簡単に変更する+ボタンの大きさを変更する 例えば、以下では、ボタンの大きさを button-2 クラスで定義して、ボタンウィジェットのクラスには、button button-balanced button-2 を設定している。 // ボタンウィジェットのスタイル設定 .button-2 { margin: 1px; // 枠の外の余白 height: 30px; // ボタンの高さ min-height: 25px; // ボタンの高さ最小値、デフォルトは 47px) line-height: 23px; // 文字の行の高さ(デフォルトは 42px) padding: 0 4px; // 枠内余白(デフォルトは、上下 0、左右 12px) min-width: 25px; // ボタンの横幅最小値、デフォルトは 52px) } ボタンの背景を(半)透明にする 上記の簡単配色の場合は、クラス欄にさらに、 button-outline を追加することで、背景を透明にできる。 または、スタイルの設定にて、background: rgba(65, 105, 225, 0.7); とすることで、背景色を(半)透明にできる。(0.7 を 0 にすれば透明にできる) opacity: 0.7; などを追加してボタン全体を半透明にできる。 ボタン全体を透明にする ボタンのクラス欄に、button-clear を追加すると、押すことが可能なボタンを非表示にできる。ボタンの表示プロパティをオフにするとボタンは押せなくなってしまう点が、同じ非表示でも異なる。写真やイラストとの重ね合わせで写真やイラストに複数のボタンを埋め込んだり、ウェアラブルデバイスでボタンは見えないがボイスコマンドを使えるようにする、などの応用が考えられる。 プレビューや Vuforia View での再生時は非表示になるが、押して JavaScriptファンクションを実行できる。 尚、opacity: 0.01; でも、同様に透明なボタンにできる。 ボタンの構成要素 ボタン表示は、以下のような CSSボックスモデルの要素から構成されているとのこと。Vuforia Studioの場合、ボタンサイズを小さくしたい場合には、min-height(heightの最小値)と line-height がデフォルトで設定されていることで高さの制限があり、min-width(widthの最小値)と padding がデフォルトで設定されていることで横幅の制限がある点に注意が必要だった。 ボタンにイメージを使う これまでは、文字を表示するボタンについて記してきた。次は、ボタン上にイメージを表示する方法について記す。 イメージボタンにする(イメージを登録して使う) ・CSS を使用したイメージボタンの作成 @Vuforia Studioヘルプ に、作成例が記載されている。これを参考に、試してみる。以下のクラスを追加する。 // イメージを背景に使う設定 .image-1, .image-1.activated { background-image: url(#{$resources}/Uploaded/btn_1_sm.png); // 背景イメージ background-repeat: no-repeat; // 背景イメージは繰り返しなしで拡大 background-position: center; // 背景イメージの位置 } // クリック時にイメージ背景を暗くする設定 .image-1.activated { -webkit-filter: opacity(30%) drop-shadow(1px 1px 0px gray); } この例では、 btn_1_sm.png というファイル名のイメージを使う。そこで、画面左下のリソースに緑の+ボタンをクリックしてファイル選択してアップロードする。 ボタンウィジェットのクラスに、上記の image-1 を入力して指定する。すると、ボタンの背景として登録したイメージが表示された。この方法では、ボタンウィジェットのテキストに表示文字を指定すれば、イメージと文字の組合せボタンを作成できる。 プレビューしてみる。クリックすると、暗くする設定の通りに暗くなった。 アイコンボタンにする(Ionicアイコンを使う) ・ 【AR】Vuforia Studioで作った画面を少し飾り付けたい by PentagonJrさん では、Ionic framework の CSS Components を使い、文字ボタンでなくアイコンボタンに変更する方法が記載されている。こちらも是非ご一読を。 ボタンウィジェットでなく、切り替えボタンウィジェットを使う 実は、この切り替えボタンウィジェットを使う方法が一番簡単な方法だと思う。 切り替えボタンウィジェットをドラッグ&ドロップで配置後、ボタンを押したときのイメージ、ボタンを押していないときのイメージ、背景色、ボタンを押したときの背景色、幅、高さ、などを指定すればよい。押しているときと押していないときの値を同じにして、イベントのクリックの JS に実行する JavaScriptのファンクションを指定すれば、ボタンと同様に機能する。 おわりに コンテンツの作成工数を考えると、デフォルトのボタンのままで使えるのであれば、それが最もよい。しかし、画面サイズの制約、色合いの関係、半透明にして背後も見えるようにする、などでボタンのスタイルの変更が必要な場面はある。スタイルの変更には、この備忘録が必ず役に立つはず。色、サイズ、透明化など用意済のクラスを指定することで簡単に変更できればよし。どうしても詳細なスタイル設定が必要となれば、この備忘録を参考に設定できるだろう。 参考 ・ボタン @Vuforia Studioヘルプ ・CSS を使用したイメージボタンの作成 @Vuforia Studioヘルプ ・ 【AR】Vuforia Studioで作った画面を少し飾り付けたい by PentagonJrさん ・Vuforia Studio で作成できるAR例~タブレットAR例、3D形状の特徴で実物にARを重畳(モデルターゲット)、2D画面上の表示や操作を組合せ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JSでcssのクラスを追加・削除する方法(Jqueryを使わない)

JavascriptでClassを追加・削除する方法を毎回忘れてしまうので、 備忘録として記載残しておきます。 index.html <style> .addclass { color: red; } </style> <button id="addButton" onclick="addclass()">テスト文字です</button> <button onclick="delclass()">クラス削除</button> <script> //#addButtonへクラスを追加します function addclass() { const buttonstyle = document.getElementById("addButton"); buttonstyle.classList.add("addclass"); } //クラスを削除します function delclass() { const buttonstyle = document.getElementById("addButton"); buttonstyle.classList.remove("addclass"); } </script> jQueryに慣れてしまうといざというときにできなかったりするのでメモしておきます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascriptを使って音声認識チャットアプリを作った

はじめに みなさま、ゴールデンウィークはいかがお過ごしでしょうか。コロナの影響で外出もしづらい状態になっています。GW中に以下の本を買って読んでいて、フロントエンド開発で手を動かしたくなったので「音声認識チャットアプリ」を作ってみたいと思います。フロントエンド の苦手克服がテーマです。 成果物のイメージはこちらです。 成果物は以下のGithub(qiita0502ブランチ)にあげてあります。 機能説明について、【Button】をクリックすることにより, 音声認識を開始します。音声はリアルタイムで書き込み、そのまま出力します。また、その音声認識結果に対して、応答文章を生成し、右側に表示します。 本記事は、以下の順を追って解説していきたいと思います。 システム設計 (本記事) Javascript の環境構築 (本記事) フロントエンドの実装 (本記事) バックエンドの実装 開発環境について、私はMac Book Pro (MacOS) を使用しました。基本的にMacユーザであれば不自由なく実装できるかと思います。 システム設計 まずはじめにシステムの全体像を確認します。端末はブラウザが動作するPCおよびWebサーバです。処理の流れは以下になります。 フロントエンド(ブラウザサイド)で発話した言葉の音声認識を行い、文章単位にわけます 文章単位でバックエンドのサーバに送ります バックエンドAPIサーバでは、受け取った文章を元に応答文を考え、それをフロントエンドに返します フロントエンドは応答文を受け取り、表示します。 目標としてJavascriptの習熟があるので、フロントエンドはJavascriptで書き上げます。 バックエンドはPythonによりAPIサーバを実装します。フロントエンドとの通信は非同期のHTTP通信によって実現します。 環境構築 実装環境を構築します。今回は今後の拡張とモダンJavascriptを踏まえ、WebPackを使用します。 実装を始める前に以下を行い、環境を構築します。 Nodejsを導入 yarnの導入 WebPackを導入 Babelを導入 Nodejsを導入 以下のサイトにアクセスし、Macのインストーラーをダウンロードして、インストールを行います。 同時にNPM(Nodeのパッケージマネージャー)もインストールされます。執筆時点での私の環境に入った各ソフトのバージョンは以下でした。 Node → v14.16.1 npm → 6.14.12 ちなみにパッケージマネージャーとは第三者の作ったライブラリなどを導入する際に、各ライブラリのバージョンを管理できるソフトウェアです。NPMはノード用のパッケージマネージャーになります。例えばRubyであれば、gemが該当します。 Yarnの導入 前述したではなく今回はyarnを利用します。モチベーションは以下です。 npmよりインストールが速い npmより厳密にモジュールのバージョンを固定できる npmと同じのpackage.jsonが使えるため、同一プロジェクトでnpm or yarnで固定しなくて良い。 以下のコマンドでnpmによりyarnを導入します。 sudo npm install -g yarn yarn → 1.22.10 WebPackの導入 以下の記事が非常に参考になります(ほぼこれ通り)。 WebPackは複数のJavascript等アセットファイルを一つのファイルに合成することができます。例えば複数のJavascriptファイルを一つのファイル(例えばbundle.js)に合成し、そのファイルのみをHTMLファイルから読み込むことでフロントサイド側での複数jsファイルの読み込み記述の省略することができます。 Webpackは箱みたいなもので、ユーザの利便性に合わせ自由に機能をして開発を行うことができます。例えば有名なBabelなどのローダー(機能だと思ってもらって結構です)を追加することで、ECMAScript2015 (ES2015)などの新標準のJavascriptの文法を従来仕様のJavascript文法に変換(トランスコンパイラー)してブラウザ間の対応/非対応に適応したコードにすることができます。 mkdir voice_test // 1. テストディレクトリを作成 yarn init // 2. 初期化。色々聞かれるので入力していく。終えるとpackage.jsonが作成される yarn add webpack webpack-cli --dev // 3. webpackの導入(CLI操作も可能にする) //node_modules //package.json //yarn.lock //が生成される WebPackの処理の設定についてはwebpack.config.jsというファイルを作成し、記述するルールとなっている。 webpack.config.js const path = require('path'); module.exports = { //ファイル更新の監視。合成元ファイルが更新された場合、すぐさま再合成をかける。 watch: true, mode: 'development', //合成する元のファイル(複数可)の指定 entry: [ './src/js/hello.js' ], output: { //合成したファイルの出力先指定。HTMLからはbundle.jsのみ読み込めば良い filename: 'bundle.js', path: path.join(__dirname, 'public/js') } }; 作業様ディレクトリの用意 ここまででwebpackは無事動いているはずなので、実際にコードを書く準備をします。以下のようなレイアウトにしてみました。 . ├── node_modules ├── package.json ├── public │   ├── css //実際にCSSを書くディレクトリ │   ├── index.html //実際にHTMLを書くファイル │   └── js ├── src │   └── js //実際にJavascriptを書くディレクトリ ├── webpack.config.js └── yarn.lock src └── js └── hello.js //コーディングするJavascriptファイル public ├── css │   └── template.css //コーディングするCSSファイル ├── index.html //コーディングするHTMLファイル └── js └── bundle.js//Webpackにより合成されたJavascript Webpack実行 ここまで終えたら以下のコマンドを実行して動くかテストしましょう。 yarn run webpack パッケージマネージャーの威力を見るために、今回の実装にjqueryを導入してみたいと思います(おまけ)。 yarn add jquery すると以下のようにdependenciesにjqueryが追加されます。これで先ほどのhello.jsからjqueryをimport等して使用することができます。 { "name": "qiita_demo", "version": "1.0.0", "main": "index.js", "license": "MIT", "devDependencies": { "webpack": "^5.36.2", "webpack-cli": "^4.6.0" }, "dependencies": { "jquery": "^3.6.0" } } フロントエンドの開発 フロントエンド用ファイルの準備 GitHubのホームページからgit clone(qiita0502ブランチ)し、必要ファイルをダウンロードしてみてください。 また、上記の階層に、所定のファイルをコピーしてみてください。 index.html/template.css/hello.js あたりが必要になると思います。 使用した基本的なテンプレート→HTML, CSS レイアウト等の話なので、今回は割愛します。これでファイルが所定の位置に置かれたと思いますので、以下のコマンドを実行し、jsファイルを合成してください。 yarn run webpack index.htmlをダブルクリックなどでブラウザから開くと成果物のアプリの画面が見れるはずです。これでひとまず、成果物の動作環境は構築できました。 フロントエンドの実装内容 今回の実装の大部分は、以下のブログで解説されているコードを元に開発しました。音声認識の部分です。こちらのブログで解説されていた内容では、ブラウザに向かって読み上げた音声を認識し、文字としてHTMLファイル中の 段落id="result"の箇所に追加するというものです。 今回、追加機能として必要なのが以下です。 ボイスの切れ目で一旦文章として区切る 文章として区切った文字列をサーバに対して送る サーバーから応答文章をもらい、表示する ボイスの切れ目で文章として区切る 発話中はonResultイベント関数が実行されています。発話の切れ目になるとクラス名に"final"が追加されたpタグが生成されます。 本アプリでは、トークスタート時のボタンクリックアクションをユーザが行なった際、別軸でタイマー関数を発火させ、get_talkを呼び出します。 get_talkは1500msecに一度、クラス名が"final"であるものの最新をチェックし、直前に保存したものと異なる場合には新しいユーザの発話とみなし、APIサーバへ送信します(実装中のrequest_callback)。 また、その結果をDOMツリーに追加します(add_response)。 文字列をAPIサーバに送る → 応答文をもらい、表示する 先にフロントエンドの開発を進めたいので、フロントエンド側に指定文字列をサーバに送る関数request_callbackを実装しました。本記事の段階では、実際にAPIサーバには送っていません。本記事の実装では、request_callback内部で応答文章作成の関数echoを呼びます。 echo関数は元の文章に"Me Too"を足した文字列を生成する関数です。(繰り返しますが、本来は応答文章はバックエンドAPIサーバ側で生成します。この部分の実装は次の記事に回します。) 実際のJSコード 以下に、実際のコードを掲載します。(githubのコードと同じです。) hello.js /*応答文章の生成. 本来はAPIサーバー側の実装. */ const echo = (text) => { return text + ": Me Too"; }; /*文章をAPIサーバーに送り, 応答文章を取得する. */ const request_callback = (text) => { let callback = echo(text); return callback; }; /*ボタンを押されている間, タイマーにより定期的に呼ばれる関数. 最新のfinalクラスのコンテンツを取得し、直前のものと比較する. 異なる場合には新しい発話が文章として見なされたとみなし、APIサーバーに送信する. */ const get_talk = () => { const $final_talk = document.getElementsByClassName("final"); if ($final_talk.length !== 0) { if(last_talk !== $final_talk[$final_talk.length - 1].textContent){ last_talk = $final_talk[$final_talk.length - 1].textContent; add_response(request_callback(last_talk)); } } }; /*応答文章のDOMツリーへの反映*/ const add_response = (text) => { const $response = document.getElementById("response"); const text_node = document.createTextNode(text); const $p = document.createElement("p"); $p.classList.add("fin_response"); $p.appendChild(text_node); $response.appendChild($p); }; /*応答文章の削除*/ const remove_all_response = () => { const $response = document.getElementById("response"); while ($response.firstChild) { $response.removeChild($response.firstChild); } }; let speechRecognition = new webkitSpeechRecognition(); speechRecognition.onresult = console.log; speechRecognition.start(); let intervalId; window.addEventListener("DOMContentLoaded", () => { const $button1 = document.getElementById("button1"); const $result = document.getElementById("result"); const $main = document.getElementById("main"); const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition if (typeof SpeechRecognition === "undefined") { $button1.remove(); const message = document.getElementById("message"); message.removeAttribute("hidden"); message.setAttribute("aria-hidden", "false"); } else { // good stuff to come here let listening = false; const recognition = new SpeechRecognition(); const start = () => { recognition.start(); $button1.textContent = "Stop listening"; $main.classList.add("speaking"); remove_all_response(); intervalId = setInterval(get_talk, 1500); }; const stop = () => { recognition.stop(); $button1.textContent = "Start listening"; $main.classList.remove("speaking"); clearInterval(intervalId); last_talk = ""; }; const onResult = event => { $result.innerHTML = ""; for (const res of event.results) { const text = document.createTextNode(res[0].transcript); const p = document.createElement("p"); if (res.isFinal) { p.classList.add("final"); } p.appendChild(text); $result.appendChild(p); } }; recognition.continuous = true; recognition.interimResults = true; recognition.addEventListener("result", onResult); $button1.addEventListener("click", () => { listening ? stop() : start(); listening = !listening; }); } }); /* talk words*/ let last_talk = ""; おわりに 今回の記事では、Javascriptの開発環境をWebpackをベースに構築し、githubのコードを動かして見ました。また、フロントエンドの実装を解説しました。次回はAPIサーバとの連携について書き、チャットの会話っぽく進化させます。 (目標, GW中!!)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsでフォームを作成していたときに知った2点

はじめに プログラミング初学者のため、自分の理解できている範囲内で言語化しています。 何か間違っている情報や改善点などありましたら、コメントいただけますと幸いです。?‍♂️ 今回はRailsでフォームを作るときにハマったことを紹介しています。 1 エラーメッセージ 表示によるレイアウトの形崩れ バリデーションエラーの文言を表示したときに、元のレイアウトが崩れてしまう問題が発生、、、 原因: field_with_errorsクラスを持つdivタグの出現 エラーメッセージを表示するときは、検証するとわかるが、field_with_errorsクラスのdivが現れる。 これによって形崩れしていた? 解決策 他にもあるが、ここではCSSに追記をするだけで良い方法を紹介 .field_with_errors { display: contents; } これを追記するだけ。 2 text-areaの縮小拡大について text-areaはデフォの状態では、横と縦にドラッグすることで縮小や拡大が可能だが、 今回の実装の際には左右の縮小はいらなかったので、その抑制方法の紹介 方法 textarea{ resize: vertical; } これで横の縮小を抑制できる 横方向 → vertical 縦方向 → horizontal 全方向 → both デフォでなっている 縮小無 → none 参考文献
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む