<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0" xml:lang="ja">
<channel>
<title>appleple</title>
<link>http://www.appleple.com/</link>
<atom:link href="https://www.appleple.com/rss2.xml" rel="self" type="application/rss+xml" />
<description></description>
<language>ja</language>
<copyright>©️ 2004 appleple Inc.</copyright>
<lastBuildDate>Fri, 07 Aug 2026 04:04:10 +0900</lastBuildDate>
<generator>a-blog cms</generator>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<item>
<dc:creator>appleple</dc:creator>
<title>夏季休業日のお知らせ</title>
<link>https://www.appleple.com/news/entry-1470.html</link>
      <description><![CDATA[


















































<!-- 余白 -->
















<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>平素は格別のご愛顧をいただき、心から御礼申し上げます。<br />
誠に勝手ながら以下の期間を夏季休業日とさせていただきます。<br />
期間中の通常業務（CMS関連事業・Webサイト制作事業・CRM関連事業）は休業となります。<br />
<br />
<br />
<em>休業期間：2026年8月11(火)〜8月16日(日) 迄</em><br />
<br />
休業中に頂いたお問い合わせについては、休業期間終了後に順次回答させていただきます。<br />
ご迷惑をおかけしますが、ご了承のほどよろしくお願いいたします。<br />
<br />
※コワーキングスペースの休業日については、<a href="https://basecamp-nagoya.jp/">ベースキャンプ名古屋のWebサイト</a>をご覧ください。<br />
</p>
  
</div>













































<!-- 余白 -->


























































<!-- 余白 -->










]]></description>
<guid isPermaLink="true">https://www.appleple.com/news/entry-1470.html</guid>
<pubDate>Thu, 23 Jul 2026 09:01:21 +0900</pubDate>
</item>
<item>
<dc:creator>appleple</dc:creator>
<title>奄美大島での社員旅行レポート</title>
<link>https://www.appleple.com/blog/event-report/trip_2026.html</link>
      <description><![CDATA[


















































<!-- 余白 -->
















<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>6月の3日間、<a href="https://www.appleple.com/blog/event-report/trip_2025.html">去年</a>に引き続き、SANU 2nd Home for Business を利用して社員旅行に行ってきました。今年の行き先は、奄美大島です！</p>
  
</div>













































<!-- 余白 -->














<hr class="clearHidden">





























<!-- media -->
<div class="column-media-auto acms-col-sm-12 ">

<a href="https://www.appleple.com/media/002/202606/CM204235.jpg?v=20260618112339" rel="prettyPhoto[1469]">
<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202606/mode3_w920-CM204235.jpg?v=20260618112339"
 width="920"
 height="517"
 alt="">
</a>


</div>



















<!-- 余白 -->
















<!-- テキスト -->
<div class="entry-text-unit">
  
  <h2 >1日目</h2>
  
</div>













































<!-- 余白 -->
















<!-- テキスト -->
<div class="entry-text-unit">
  
  <h3 >奄美自然観察の森</h3>
  
</div>













































<!-- 余白 -->












<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">



<hr class="clearHidden">





























<!-- media -->
<div class="column-media-auto acms-col-sm-12 ">

<a href="https://www.appleple.com/media/002/202606/IMG_6639.jpg?v=20260618111644" rel="prettyPhoto[1469]">
<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202606/mode3_w920-IMG_6639.jpg?v=20260618111644"
 width="920"
 height="517"
 alt="">
</a>


</div>



















<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>


<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">





<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>チェックイン前にまずは軽く森を散策。まだ奄美に慣れないのでみんな巨大ナメクジやザトウムシに大騒ぎでした。「キョロロロロ」と下がっていくメロディーの謎めいた鳥の鳴き声も。梅雨時で曇ってはいましたが、展望台から見渡す龍郷湾の景色は最高でした。</p>
  
</div>













































<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>




<hr class="clearHidden">



<!-- テキスト -->
<div class="entry-text-unit">
  
  <h3 >SANU 2nd Home 奄美大島1st</h3>
  
</div>













































<!-- 余白 -->












<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">



<hr class="clearHidden">





























<!-- media -->
<div class="column-media-center acms-col-sm-12 ">

<a href="https://www.appleple.com/media/002/202606/CM204253.jpg?v=20260618111625" rel="prettyPhoto[1469]">
<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202606/mode3_w920-CM204253.jpg?v=20260618111625"
 width="920"
 height="517"
 alt="">
</a>


</div>



















<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>


<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">





<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>チェックインしていったん休憩。亜熱帯の気候に合わせた高床式の各棟からは赤尾木湾を見渡すことができました。</p>
  
</div>













































<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>




<hr class="clearHidden">



<!-- テキスト -->
<div class="entry-text-unit">
  
  <h3 >ナイトサファリツアー</h3>
  
</div>













































<!-- 余白 -->












<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-4">



<hr class="clearHidden">





























<!-- media -->
<div class="column-media-center acms-col-sm-12 ">

<a href="https://www.appleple.com/media/002/202606/IMG_6031.jpg?v=20260618111708" rel="prettyPhoto[1469]">
<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202606/mode3_w920-IMG_6031.jpg?v=20260618111708"
 width="920"
 height="517"
 alt="">
</a>


</div>



















<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>


<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-4">



<hr class="clearHidden">





























<!-- media -->
<div class="column-media-auto acms-col-sm-12 ">

<a href="https://www.appleple.com/media/002/202606/DSC_6816_1.jpg?v=20260618111728" rel="prettyPhoto[1469]">
<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202606/mode3_w920-DSC_6816_1.jpg?v=20260618111728"
 width="920"
 height="517"
 alt="">
</a>


</div>



















<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>


<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-4">



<hr class="clearHidden">





























<!-- media -->
<div class="column-media-auto acms-col-sm-12 ">

<a href="https://www.appleple.com/media/002/202606/DSC_6882.jpg?v=20260618111744" rel="prettyPhoto[1469]">
<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202606/mode3_w920-DSC_6882.jpg?v=20260618111744"
 width="920"
 height="517"
 alt="">
</a>


</div>



















<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>




<hr class="clearHidden">



<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>夜はゆっくりと食事を楽しむチームとナイトサファリツアーに参加するチームに分かれて行動。ナイトサファリツアーではジープに乗ってガイドの説明をききながら、さまざまな野性動物を観察しました。アマミノクロウサギはもちろん、お昼に聞いた謎の鳴き声の主、リュウキュウアカショウビンにも遭遇してテンションが上りました。</p>
  
</div>













































<!-- 余白 -->














<hr class="clearHidden">



<!-- テキスト -->
<div class="entry-text-unit">
  
  <h2 >2日目</h2>
  
</div>













































<!-- 余白 -->














<hr class="clearHidden">



<!-- テキスト -->
<div class="entry-text-unit">
  
  <h3 >金作原原生林散策トレッキング</h3>
  
</div>













































<!-- 余白 -->












<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">



<hr class="clearHidden">





























<!-- media -->
<div class="column-media-auto acms-col-sm-12 ">

<a href="https://www.appleple.com/media/002/202606/CM204299.jpg?v=20260618111805" rel="prettyPhoto[1469]">
<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202606/mode3_w920-CM204299.jpg?v=20260618111805"
 width="920"
 height="517"
 alt="">
</a>


</div>



















<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>


<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">





<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>2日目の午前は金作原原生林。樹齢二百年のオキナワウラジロガシまでの往復5キロのコースを認定ガイドの説明を聞きながら散策しました。植物では他にヒカゲヘゴ、クワズイモ、月桃など。</p>
  
</div>













































<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>


<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">



<hr class="clearHidden">





























<!-- media -->
<div class="column-media-auto acms-col-sm-12 ">

<a href="https://www.appleple.com/media/002/202606/CM204307.jpg?v=20260618111822" rel="prettyPhoto[1469]">
<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202606/mode3_w920-CM204307.jpg?v=20260618111822"
 width="920"
 height="516"
 alt="">
</a>


</div>



















<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>


<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">





<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>動物ではオキナワキノボリトカゲ、アマミシリケンイモリなど。姿は見えませんでしたが、アカヒゲという鳥の声も素晴らしかったです。そしてとぐろを巻いたヒメハブも！</p>
  
</div>













































<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>




<hr class="clearHidden">



<!-- テキスト -->
<div class="entry-text-unit">
  
  <h3 >マングローブカヌー体験</h3>
  
</div>













































<!-- 余白 -->












<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">



<hr class="clearHidden">





























<!-- media -->
<div class="column-media-center acms-col-sm-12 ">

<a href="https://www.appleple.com/media/002/202606/IMG_3879.jpg?v=20260618111848" rel="prettyPhoto[1469]">
<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202606/mode3_w920-IMG_3879.jpg?v=20260618111848"
 width="920"
 height="517"
 alt="">
</a>


</div>



















<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>


<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">





<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>午後はマングローブ原生林でカヌー体験。多少雨が降ってきましたが、カヌーではどうせ濡れるのでそれほど気になりませんでした。狭いトンネルのような場所と開けた河口の対比が面白く、一瞬たりとも飽きない景観でした。ミナミトビハゼやカニ、ミナミクロダイを発見した人も！</p>
  
</div>













































<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>




<hr class="clearHidden">



<!-- テキスト -->
<div class="entry-text-unit">
  
  <h2 >3日目</h2>
  
</div>













































<!-- 余白 -->














<hr class="clearHidden">



<!-- テキスト -->
<div class="entry-text-unit">
  
  <h3 >奄美パーク</h3>
  
</div>













































<!-- 余白 -->












<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">



<hr class="clearHidden">





























<!-- media -->
<div class="column-media-auto acms-col-sm-12 ">

<a href="https://www.appleple.com/media/002/202606/IMG_6186.jpg?v=20260618111923" rel="prettyPhoto[1469]">
<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202606/mode3_w920-IMG_6186.jpg?v=20260618111923"
 width="920"
 height="517"
 alt="">
</a>


</div>



















<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>


<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">





<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>3日目は雨が本降りになったので屋内で楽しめる奄美パークへ。奄美大島の歴史やくらしについて知り、奄美に移住し、数々の傑作をのこした画家、田中一村の美術館を堪能しました。</p>
  
</div>













































<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>




<hr class="clearHidden">



<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>奄美大島での3日間、非常に楽しく、チームの親睦も深まりました。フレッシュな気持ちで今年後半のお仕事に取り組んでまいります！</p>
  
</div>













































<!-- 余白 -->


























































<!-- 余白 -->










]]></description>
<category>イベントレポート</category>
<guid isPermaLink="true">https://www.appleple.com/blog/event-report/trip_2026.html</guid>
<pubDate>Wed, 17 Jun 2026 15:39:35 +0900</pubDate>
</item>
<item>
<dc:creator>appleple</dc:creator>
<title>2026年度入社式を行いました</title>
<link>https://www.appleple.com/blog/Internal-Initiatives/join2026.html</link>
      <description><![CDATA[


















































<!-- 余白 -->
















<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>4月1日（水）に、2026年度入社式が行われ、フロントエンドエンジニアとして 山中 弥琴（やまなか みこと）さんを迎え入れました。</p>
  
</div>













































<!-- 余白 -->














<hr class="clearHidden">





























<!-- media -->
<div class="column-media-center acms-col-sm-12 ">

<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202604/mode3_w920-CM203925_1.jpg?v=20260413120421"
 width="920"
 height="613"
 alt="">
<p class="caption">ウェルカムボード（Welcome to appelple 2026.04.01 山中弥琴さん）とウェルカムフラワー</p>


</div>



















<!-- 余白 -->














<hr class="clearHidden">



<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>実は山中さんと私たちの出会いは、今から約半年前の2025年夏に遡ります。<br />
最初は3日間の短期インターンからのスタートでした。その後、今年の春まで長期インターンとして、熱心に業務に取り組んでくれました。</p>
  
</div>













































<!-- 余白 -->












<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">



<hr class="clearHidden">





























<!-- media -->
<div class="column-media-center acms-col-sm-12 ">

<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202604/mode3_w920-CM203956.jpg?v=20260413121238"
 width="920"
 height="613"
 alt="">
<p class="caption">永富さんによる歓迎の言葉</p>


</div>



















<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>


<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">



<hr class="clearHidden">





























<!-- media -->
<div class="column-media-auto acms-col-sm-12 ">

<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202604/mode3_w920-CM203963.jpg?v=20260413121441"
 width="920"
 height="613"
 alt="">
<p class="caption">山中さんによる答辞</p>


</div>



















<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>






<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>入社式では、少し緊張しながらも、インターン時より一層たくましくなった山中さんの表情が印象的でした。<br />
地道な努力を積み重ね、一つひとつスキルを自分のものにしていく姿を間近で見てきたからこそ、今日という日を迎えられた喜びもひとしおです。</p>
  
</div>













































<!-- 余白 -->












<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">



<hr class="clearHidden">





























<!-- media -->
<div class="column-media-auto acms-col-sm-12 ">

<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202604/mode3_w920-CM203942.jpg?v=20260413122212"
 width="920"
 height="613"
 alt="">
<p class="caption">代表山本による挨拶</p>


</div>



















<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>


<!-- ユニットグループの開始タグ -->
<div class="js-unit_group-align acms-entry-unit-full acms-col-sm-6">



<hr class="clearHidden">





























<!-- media -->
<div class="column-media-auto acms-col-sm-12 ">

<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202604/mode3_w920-CM203948_1.jpg?v=20260413120903"
 width="920"
 height="613"
 alt="">
<p class="caption">辞令交付の様子</p>


</div>



















<!-- 余白 -->











<!-- ユニットグループの終了タグ -->
</div>






<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>新しいメンバーと共に、より一層パワーアップしたアップルップルを今後ともよろしくお願いいたします！</p>
  
</div>













































<!-- 余白 -->














<hr class="clearHidden">





























<!-- media -->
<div class="column-media-center acms-col-sm-12 ">

<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202604/mode3_w920-CM203985.jpg?v=20260413122421"
 width="920"
 height="654"
 alt="">
<p class="caption">記念写真</p>


</div>



















<!-- 余白 -->


























































<!-- 余白 -->










]]></description>
<category>社内の取り組み</category>
<guid isPermaLink="true">https://www.appleple.com/blog/Internal-Initiatives/join2026.html</guid>
<pubDate>Wed, 01 Apr 2026 10:00:00 +0900</pubDate>
</item>
<item>
<dc:creator>appleple</dc:creator>
<title>コードブロックにアクセシブルなコピーボタンを追加する方法</title>
<link>https://www.appleple.com/blog/code-block-copy-button.html</link>
      <description><![CDATA[


















































<!-- 余白 -->










































<!-- media -->
<div class="column-media-auto acms-col-sm-12 ">

<a href="https://www.appleple.com/media/002/202602/thumbnail.png?v=20260203120917" rel="prettyPhoto[1463]">
<img class="js-lazy-load columnImage"
 src="/themes/system/images/placeholder/image.svg"
 data-src="https://www.appleple.com/media/002/202602/mode3_w920-thumbnail.png?v=20260203120917"
 width="920"
 height="483"
 alt="">
</a>


</div>



















<!-- 余白 -->
















<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>この記事では、a-blog cms のブロックエディターで生成されるコードブロックに、アクセシビリティに配慮したコピーボタンを追加する実装方法をご紹介します。</p>

  
</div>













































<!-- 余白 -->
















<!-- テキスト -->
<div class="entry-text-unit">
  
  <h2>ブロックエディターのHTML構造を理解する</h2>
<p>a-blog cms のブロックエディターは Tiptapを使用しており、コードブロックは以下のようなシンプルなHTMLとして出力されます。</p>
<pre><code class="html">&lt;div class="column-block-editor"&gt;
  &lt;pre&gt;// ここにコードが入ります&lt;/pre&gt;
&lt;/div&gt;
</code></pre>
<h3>HTML構造の解説</h3>
<ul>
<li><strong><code>&lt;pre&gt;</code> タグ</strong>：コードブロックの本体</li>
<li><strong><code>&lt;div class="column-block-editor"&gt;</code></strong>：ラップしている div タグ</li>
</ul>
<p>このラップ用の div タグは、<code>system/_layouts/unit.html</code> の <code>@section(block-editor)</code> で定義されており、任意で追加できます。標準でこのクラスが付与されている理由は以下の通りです。</p>
<ul>
<li>ブロックエディター内に限定したスタイル制御が容易</li>
<li>ユニット毎に要素を明確に分けられる</li>
</ul>

  
</div>













































<!-- 余白 -->
















<!-- テキスト -->
<div class="entry-text-unit">
  
  <h2>アクセシビリティに配慮した実装方法</h2>
<h3>完全なコード</h3>
<p>以下が、アクセシビリティに配慮したコピーボタンを追加するためのJavaScriptコードです。</p>
<pre><code class="javascript">const preElements = document.querySelectorAll('.column-block-editor pre');

if (preElements.length === 0) return;

function addCopyButton(codeBlock) {
  // 既にラップされている場合はスキップ
  if (codeBlock.parentElement.classList.contains('code-block-wrapper')) {
    return;
  }

  // コピーボタンを作成
  const button = document.createElement('button');
  button.type = 'button';
  button.className = 'code-copy-button';
  button.textContent = 'コピー';
  button.setAttribute('aria-label', 'コードをコピー');

  // ライブリージョンを作成（スクリーンリーダーへの通知用）
  const liveRegion = document.createElement('span');
  liveRegion.className = 'visually-hidden';
  liveRegion.setAttribute('role', 'status');
  liveRegion.setAttribute('aria-live', 'polite');
  liveRegion.setAttribute('aria-atomic', 'true');

  // ボタンのクリックイベント
  button.addEventListener('click', async () =&gt; {
    try {
      const code = codeBlock.textContent;
      await navigator.clipboard.writeText(code);

      // コピー成功のフィードバック
      button.textContent = 'コピーしました!';
      button.setAttribute('aria-label', 'コードをコピーしました');
      liveRegion.textContent = 'コードをクリップボードにコピーしました';

      // 2秒後に元に戻す
      setTimeout(() =&gt; {
        button.textContent = 'コピー';
        button.setAttribute('aria-label', 'コードをコピー');
        liveRegion.textContent = '';
      }, 2000);
    } catch (error) {
      button.textContent = 'エラー';
      button.setAttribute('aria-label', 'コピーに失敗しました');
      liveRegion.textContent = 'コピーに失敗しました。もう一度お試しください';

      setTimeout(() =&gt; {
        button.textContent = 'コピー';
        button.setAttribute('aria-label', 'コードをコピー');
        liveRegion.textContent = '';
      }, 2000);
    }
  });

  // pre要素をラップするコンテナを作成
  const wrapper = document.createElement('div');
  wrapper.className = 'code-block-wrapper';
  const parent = codeBlock.parentNode;
  parent.insertBefore(wrapper, codeBlock);
  wrapper.appendChild(codeBlock);
  wrapper.appendChild(button);
  wrapper.appendChild(liveRegion);
}

// 各 pre 要素に対してコピーボタンを追加
preElements.forEach(codeBlock =&gt; {
  addCopyButton(codeBlock);
});
</code></pre>

  
</div>













































<!-- 余白 -->
















<!-- テキスト -->
<div class="entry-text-unit">
  
  <h3>コードの処理フロー</h3>
<h4>1. コードブロックの検出</h4>
<pre><code class="javascript">const preElements = document.querySelectorAll('.column-block-editor pre');
if (preElements.length === 0) return;
</code></pre>
<p>ページ内のすべてのコードブロック（<code>pre</code> タグ）を取得します。コードブロックが存在しない場合は処理を終了します。</p>
<h4>2. 重複チェック</h4>
<pre><code class="javascript">if (codeBlock.parentElement.classList.contains('code-block-wrapper')) {
  return;
}
</code></pre>
<p>既にコピーボタンが追加されている場合はスキップします。これにより、同じコードブロックに複数のボタンが追加されるのを防ぎます。</p>
<h4>3. コピーボタンの作成</h4>
<pre><code class="javascript">const button = document.createElement('button');
button.type = 'button';
button.className = 'code-copy-button';
button.textContent = 'コピー';
button.setAttribute('aria-label', 'コードをコピー');
</code></pre>
<p><strong>アクセシビリティのポイント</strong>：</p>
<ul>
<li><strong><code>type="button"</code></strong>: フォーム内で使用された場合の意図しない送信を防止</li>
<li><strong><code>aria-label</code></strong>: スクリーンリーダーがボタンの目的を明確に読み上げられるようにする</li>
<li><strong><code>textContent</code></strong>: 視覚的なラベルを提供</li>
</ul>
<h4>4. ライブリージョンの作成</h4>
<pre><code class="javascript">const liveRegion = document.createElement('span');
liveRegion.className = 'visually-hidden';
liveRegion.setAttribute('role', 'status');
liveRegion.setAttribute('aria-live', 'polite');
liveRegion.setAttribute('aria-atomic', 'true');
</code></pre>
<p><strong>ライブリージョンとは</strong>：</p>
<p>ライブリージョンは、ページの内容が動的に変更されたときに、その変更をスクリーンリーダーユーザーに自動的に通知するための仕組みです。</p>
<p><strong>各属性の役割:</strong></p>
<ul>
<li><strong><code>role="status"</code></strong>：ステータスメッセージであることを示す</li>
<li><strong><code>aria-live="polite"</code></strong>：現在の読み上げを中断せず、終了後に通知する</li>
<li><strong><code>aria-live="assertive"</code>と異なる点</strong>：緊急性が低いメッセージに適している</li>
<li><strong><code>aria-atomic="true"</code></strong>：内容全体を読み上げる（部分的ではなく）</li>
</ul>
<p><strong>なぜボタンに <code>aria-live</code> を付けないのか</strong>：</p>
<p>ボタンに直接 <code>aria-live</code> を設定することも技術的には可能ですが、以下の理由から推奨されません。</p>
<ul>
<li>ボタンは「操作する要素」であり、「状態を通知する要素」ではない</li>
<li>フォーカスがボタンにある状態では通知が不安定になる場合がある</li>
<li>役割を分離することで、より確実でメンテナンスしやすいコードになる</li>
</ul>
<h4>5. クリップボードへのコピー機能</h4>
<pre><code class="javascript">button.addEventListener('click', async () =&gt; {
  try {
    const code = codeBlock.textContent;
    await navigator.clipboard.writeText(code);

    // 視覚的フィードバック
    button.textContent = 'コピーしました!';
    button.setAttribute('aria-label', 'コードをコピーしました');

    // スクリーンリーダーへの通知
    liveRegion.textContent = 'コードをクリップボードにコピーしました';

    // 2秒後に元に戻す
    setTimeout(() =&gt; {
      button.textContent = 'コピー';
      button.setAttribute('aria-label', 'コードをコピー');
      liveRegion.textContent = '';
    }, 2000);
  } catch (error) {
    button.textContent = 'エラー';
    button.setAttribute('aria-label', 'コピーに失敗しました');
    liveRegion.textContent = 'コピーに失敗しました。もう一度お試しください';

    setTimeout(() =&gt; {
      button.textContent = 'コピー';
      button.setAttribute('aria-label', 'コードをコピー');
      liveRegion.textContent = '';
    }, 2000);
  }
});
</code></pre>
<p><strong>アクセシビリティのポイント</strong>：</p>
<ol>
<li><strong>視覚的フィードバック</strong>：<code>button.textContent</code> の変更で、視覚ユーザーに結果を通知</li>
<li><strong><code>aria-label</code> の動的更新</strong>：スクリーンリーダーユーザーがボタンに再フォーカスした際に、正確な状態を伝える</li>
<li><strong>ライブリージョンによる通知</strong>：フォーカス位置に関わらず、操作結果をスクリーンリーダーユーザーに通知</li>
<li><strong>状態のリセット</strong>：2秒後に元の状態に戻すことで、再試行が可能</li>
</ol>
<p><strong>try-catch を使用する理由</strong>：</p>
<p><code>navigator.clipboard.writeText()</code> は以下の状況で失敗する可能性があります。</p>
<ul>
<li>HTTPS でない環境（http ページ）</li>
<li>ユーザーがクリップボードへのアクセスを拒否している</li>
<li>一部の古いブラウザでの非対応</li>
<li>iframe内での実行制限</li>
</ul>
<p>try-catch により、エラーが発生してもアプリケーション全体がクラッシュせず、ユーザーに適切なフィードバックを提供できます。</p>
<h4>6. DOM構造の再構築</h4>
<pre><code class="javascript">const wrapper = document.createElement('div');
wrapper.className = 'code-block-wrapper';
const parent = codeBlock.parentNode;
parent.insertBefore(wrapper, codeBlock);
wrapper.appendChild(codeBlock);
wrapper.appendChild(button);
wrapper.appendChild(liveRegion);
</code></pre>
<p>コードブロック、ボタン、ライブリージョンを包含する wrapper div を作成し、以下のような構造に変更します。</p>
<p><strong>変更前</strong>：</p>
<pre><code class="html">&lt;div class="column-block-editor"&gt;
  &lt;pre&gt;...&lt;/pre&gt;
&lt;/div&gt;
</code></pre>
<p><strong>変更後</strong>：</p>
<pre><code class="html">&lt;div class="column-block-editor"&gt;
  &lt;div class="code-block-wrapper"&gt;
    &lt;pre&gt;...&lt;/pre&gt;
    &lt;button type="button" class="code-copy-button" aria-label="コードをコピー"&gt;
      コピー
    &lt;/button&gt;
    &lt;span class="visually-hidden" role="status" aria-live="polite" aria-atomic="true"&gt;
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<p>これにより、コードブロックとボタン、ライブリージョンを一つのコンテナで管理でき、CSS でのスタイリングが容易になります。</p>

  
</div>













































<!-- 余白 -->
















<!-- テキスト -->
<div class="entry-text-unit">
  
  <h2>スタイリング</h2>
<h3>基本的なCSS</h3>
<p>コピーボタンを右上に配置し、ライブリージョンを視覚的に非表示にする CSS です。</p>
<pre><code class="css">.code-block-wrapper {
  position: relative;
}

.code-copy-button {
  position: absolute;
  top: 8px;
  right: 8px;
  padding: 4px 12px;
  background-color: #f0f0f0;
  border: 1px solid #ccc;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  transition: background-color 0.2s;
}

.code-copy-button:hover {
  background-color: #e0e0e0;
}

.code-copy-button:focus {
  outline: 2px solid #0066cc;
  outline-offset: 2px;
}

/* スクリーンリーダー専用: 視覚的に非表示だが読み上げ可能 */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

.code-copy-button:focus {
  outline: 2px solid #0066cc;
  outline-offset: 2px;
}

/* マウスクリック時はアウトラインを非表示 */
.code-copy-button:focus:not(:focus-visible) {
  outline: none;
}
</code></pre>
<p><strong>重要な注意点</strong>：</p>
<p>ライブリージョンを視覚的に非表示にする際、<code>display: none</code> や <code>visibility: hidden</code> を使用すると、スクリーンリーダーからも隠れてしまいます。<code>.visually-hidden</code> クラスを使用することで、視覚的にのみ非表示にし、スクリーンリーダーからはアクセス可能な状態を保ちます。</p>

  
</div>













































<!-- 余白 -->
















<!-- テキスト -->
<div class="entry-text-unit">
  
  <h2>アクセシビリティのチェックリスト</h2>
<p>この実装が満たしているアクセシビリティ要件:</p>
<ul>
<li>✅ <strong>キーボード操作</strong>：ボタンは Tab キーでフォーカス可能、Enter/Space キーで操作可能</li>
<li>✅ <strong>スクリーンリーダー対応</strong>：<code>aria-label</code> とライブリージョンで適切な情報提供</li>
<li>✅ <strong>視覚的フィードバック</strong>：ボタンのテキスト変更で操作結果を表示</li>
<li>✅ <strong>音声フィードバック</strong>：ライブリージョンでスクリーンリーダーに通知</li>
<li>✅ <strong>エラーハンドリング</strong>：失敗時にも適切なフィードバック</li>
<li>✅ <strong>フォーカスインジケーター</strong>：キーボード操作時に視覚的なフォーカス表示</li>
<li>✅ <strong>セマンティックHTML</strong>：適切な要素と属性の使用</li>
</ul>

  
</div>













































<!-- 余白 -->
















<!-- テキスト -->
<div class="entry-text-unit">
  
  <h2>まとめ</h2>
<p>このスクリプトを使用することで、a-blog cms のブロックエディターで生成されるすべてのコードブロックに、アクセシビリティに配慮したコピーボタンを自動的に追加できます。</p>
<p><strong>主要なアクセシビリティ機能</strong>：</p>
<ol>
<li><strong>ボタンの明示的なタイプ指定</strong>：<code>type="button"</code> でフォーム送信を防止</li>
<li><strong>aria-label</strong>：スクリーンリーダーユーザーにボタンの目的を伝える</li>
<li><strong>ライブリージョン</strong>：動的な変更を自動的に通知</li>
<li><strong>視覚的フィードバック</strong>：すべてのユーザーに操作結果を提供</li>
<li><strong>適切なエラーハンドリング</strong>：失敗時も明確なフィードバック</li>
</ol>
<p>これにより、アクセシビリティが考慮できた快適に使用できる実装となっています。</p>

  
</div>













































<!-- 余白 -->


























































<!-- 余白 -->










]]></description>
<guid isPermaLink="true">https://www.appleple.com/blog/code-block-copy-button.html</guid>
<pubDate>Wed, 04 Feb 2026 13:44:51 +0900</pubDate>
</item>
<item>
<dc:creator>appleple</dc:creator>
<title>明けましておめでとうございます。</title>
<link>https://www.appleple.com/blog/news/new-year-2026.html</link>
      <description><![CDATA[


















































<!-- 余白 -->
















<!-- テキスト -->
<div class="entry-text-unit">
  
  <p>今年もよろしくお願いいたします。</p>
  
</div>













































<!-- 余白 -->


























































<!-- 余白 -->










]]></description>
<guid isPermaLink="true">https://www.appleple.com/blog/news/new-year-2026.html</guid>
<pubDate>Thu, 01 Jan 2026 10:00:00 +0900</pubDate>
</item>
</channel>
</rss>
