3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【ExcelJS】特定のセルだけ赤くしたつもりが、関係ないセルまで赤くなってしまった話 😱

3
Last updated at Posted at 2025-12-19

はじめに

こんにちは!
最近、業務で Node.js を使って Excel ファイルを操作する機会がありました。
ライブラリとして ExcelJS を採用したのですが、スタイルの適用で思わぬ落とし穴にはまったので、自戒を込めて共有します。

「特定のセルだけ色を変えたいのに、なぜか他のセルまで色が変わっちゃう…!」
という現象に遭遇した方の助けになれば幸いです。

やりたかったこと

ユーザーがアップロードした Excel ファイルを読み込み、入力内容にエラーがあるセル(例えば B2)の背景色を「赤」にして、エラーファイルとして返却する処理です。

イメージ

  1. Excelファイルを読み込む
  2. セル B2 の値をチェック(エラー発見!)
  3. セル B2 の背景色を赤にする
  4. 保存する

起きたこと

実装して動かしてみると、恐ろしいことが起きました。

:「よし、B2セルだけ赤くなってるかな?」
Excel:「B2も赤くしたけど、ついでにB3もB4も、なんならC列のセルも赤くしておいたよ!
:「えぇ……(困惑)」

指定していないはずのセルまで、スタイルが変更されてしまったのです。

原因:スタイルの「実体」は共有されていた

原因は、ExcelJS(および Excel ファイルそのもの)が、スタイルをメモリ節約のために「共有」していることを知らなかった点にありました。

失敗したコード

初学者だった私は、以下のように書いていました。

const workbook = new ExcelJS.Workbook();
await workbook.xlsx.readFile('template.xlsx');
const worksheet = workbook.getWorksheet(1);

const cell = worksheet.getCell('B2');

// 【NG】直接プロパティを書き換えてしまった
// これだと、このスタイルを使っている全セルに影響が出ます
cell.style.fill = {
  type: 'pattern',
  pattern: 'solid',
  fgColor: { argb: 'FFFF0000' } // 赤色
};

await workbook.xlsx.writeFile('result.xlsx');

一見良さそうに見えますが、これが罠でした。

なぜ他のセルまで変わるの?(例え話)

この現象をわかりやすく説明すると、**「回覧板」「共有のルールブック」**のような状態です。

Excel ファイルの中では、データ量を減らすために、同じ見た目のセルたちは**「1つのスタイル定義(スタイルオブジェクト)」をみんなで参照(共有)**しています。

  1. B2B3B4も、元々は「標準スタイル」という1つのルールブックを見ていました。
  2. 私は「B2セルだから」と思って、B2が持っているルールブックに赤ペンで「背景は赤!」と書き込みました。
  3. すると、同じルールブックを見ていた B3 や B4 にとっても、ルールブックの内容が「背景は赤!」に書き換わってしまったのです。

プログラミング用語で言うと、「参照渡し(Reference)」されているオブジェクトを直接変更してしまったことが原因です。

解決策:新しいスタイルオブジェクトを割り当てる

解決策はシンプルです。
「みんなで見ているルールブック」に書き込むのではなく、「そのセル専用の新しいルールブック(オブジェクト)」を作って渡してあげる必要があります。

修正後のコード

const cell = worksheet.getCell('B2');

// 【OK】現在のスタイルをコピーして、新しいオブジェクトとして割り当てる

// 1. 現在のスタイルをコピー (スプレッド構文などを使用)
// これで「共有ルールブック」のコピー(新しい実体)が作られます
const newStyle = { ...cell.style };

// 2. 新しいオブジェクトに対して変更を加える
newStyle.fill = {
  type: 'pattern',
  pattern: 'solid',
  fgColor: { argb: 'FFFF0000' }
};

// 3. セルに新しいスタイルオブジェクトをセットする
// これで、このセルは共有のスタイルから切り離されます
cell.style = newStyle;

こうすることで、ExcelJS は「お、このセルには別のスタイルが設定されたな」と判断し、他のセルに影響を与えることなく B2 セルだけを赤くしてくれます。

補足:部分的な書き換えも注意

cell.font だけ変えたい場合も同様です。
cell.font.bold = true とすると、共有されているフォント設定が書き換わる可能性があります。
cell.font = { ...cell.font, bold: true } のように、オブジェクトごと入れ替えるのが安全です。

まとめ

  • 事象: ExcelJS でセルの style プロパティの中身を直接書き換えたら、他のセルの見た目まで変わってしまった。
  • 原因: スタイルオブジェクトは複数のセルで共有(参照)されているため、大元のオブジェクトを書き換えてしまっていた。
  • 対策: cell.style.fill = ... と書くのではなく、cell.style = { ... } のように、新しいオブジェクトを作って代入することで参照を切る。

オブジェクトの参照について理解が深まる良い失敗でした!
同じ現象で悩んでいる方の参考になれば嬉しいです。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?