---
title: "Слияние и ширина: MergeCell и SetColWidth"
description: "Excelize mergecell собирает шапку в один блок, SetColWidth задаёт ширину столбцов excelize в символах, высота строк и автоширина по содержимому. С разбором."
course: "Excel в Go: чтение и генерация xlsx на excelize"
url: "https://golangmaster.ru/courses/excelize/lessons/10-obyedinenie-yacheek/"
published: "2026-09-19"
updated: "2026-09-21"
minutes: 16
---

# Слияние и ширина: MergeCell и SetColWidth

*Курс «Excel в Go: чтение и генерация xlsx на excelize», урок 10 из 25. ~16 минут. Обновлено 21.09.2026. Источник: https://golangmaster.ru/courses/excelize/lessons/10-obyedinenie-yacheek/*

Запрос excelize mergecell приходит с двумя классическими жалобами: заголовок «Отчёт за квартал» торчит из одной ячейки, обрезанный соседями, а в колонке дат вместо чисел — решётки. Обе жалобы лечатся размерами листа: слияние собирает шапку в один блок, ширина столбцов excelize отдаёт колонкам место под содержимое. В этом уроке — MergeCell и UnmergeCell, ловушки чтения файлов со слияниями, SetColWidth с честным разбором единиц, высота строк и приём автоширины по содержимому, которого в библиотеке из коробки нет.

У стилей из прошлых уроков есть слепая зона: они красят ячейки, но не двигают их. А почти каждый настоящий отчёт требует геометрии: шапка «Итоги за II квартал» растягивается над тремя колонками, длинное наименование не помещается в ячейку шириной восемь символов, строка заголовка сжимает крупный шрифт в узкую полоску. Это три отдельные ручки листа — объединение ячеек, ширина столбцов и высота строк. В отличие от стилей, они применяются не через идентификаторы, а прямыми вызовами на файле: MergeCell, SetColWidth и SetRowHeight. Объединения работают в обе стороны: шапку тянут по горизонтали над колонками, а вертикальные блоки — в декоративных зонах вроде боковика с названием раздела, хотя слияния внутри колонок данных, как увидим ниже, удовольствие сомнительное. Порядок работы свободный, но в отчётах ручки обычно проходят сверху вниз: сначала собирают шапку с объединениями, потом расставляют ширины под данные, в конце подгоняют высоты. И стили из прошлых уроков пригодятся сразу: объединённый блок красится тем же SetCellStyle, только диапазон теперь совпадает с областью слияния — на этом правиле здесь будет отдельная врезка.

### MergeCell: excelize mergecell собирает один блок

Метод f.MergeCell принимает лист и две ячейки: верхнюю-левую и нижнюю-правую будущего блока — и помечает прямоугольник как один. Вызов f.MergeCell("Отчёт", "A1", "D1") растягивает первую строку на четыре колонки, а тот же метод с координатами A10 и A20 соберёт вертикальный блок из одиннадцати строк — так оформляют боковики и зоны-разделители. Значение живёт в верхней-левой ячейке: Excel рисует его по всей площади блока, а физически остальные ячейки пусты — пишите значение до слияния или после, лишь бы по координате угла. Повторное слияние того же диапазона excelize отклонит ошибкой, как и пересечение с уже объединённым блоком: карта слияний хранится в файле, и библиотека проверяет её перед записью. Снимается слияние зеркально: UnmergeCell с теми же координатами — значение остаётся в углу, остальные ячейки снова становятся обычными. Важно понимать границы операции: слияние не склеивает тексты и не суммирует числа, это про геометрию, а не про данные. Для аудита есть GetMergeCells: вернёт список блоков листа с начальной и конечной координатами, и чужой файл разумно просматривать именно с этой карты.

### Шапка на четыре колонки

```go
f.SetCellValue("Отчёт", "A1", "Отчёт за второй квартал")

if err := f.MergeCell("Отчёт", "A1", "D1"); err != nil {
    panic(err)
}

header, err := f.NewStyle(&excelize.Style{
    Font: &excelize.Font{Bold: true, Size: 13},
    Alignment: &excelize.Alignment{
        Horizontal: "center",
        Vertical:   "center",
    },
})
if err != nil {
    panic(err)
}

if err := f.SetCellStyle("Отчёт", "A1", "D1", header); err != nil {
    panic(err)
}
```

Значение пишется в верхнюю-левую ячейку, слияние накрывает прямоугольник, стиль прикладывается тем же прямоугольником: выравнивание центрует содержимое блока, а заливка и рамки из прошлых уроков лягут на каждую ячейку. Примените стиль только к A1 — и покрашется один угол шапки.

> **Стиль — всему блоку, а не углу.** Стиль объединённой шапки прикладывайте тем же прямоугольником, что и слияние: заливка, границы и выравнивание лежат на каждой ячейке блока отдельно. Покрасили только A1 — шапка оказалась наполовину синей, а рамка обрамила один угол. Правило одной строкой: диапазон SetCellStyle совпадает с диапазоном MergeCell.

### Чтение файла со слияниями

Плата за красивую шапку приходит при чтении собственного файла. GetRows вернёт текст в первой ячейке блока и пустые строки в остальных: построчный парсер увидит строку, где три ячейки пусты, и решит, что данные кончились. GetCellValue("C1") вернёт пустую строку, хотя на экране Excel показывает заголовок по всей площади блока. Отсюда правило разделения труда: слияния — для декоративных зон, заголовков, подписей и периодов; данные живут по одной ячейке на значение. Шапку объединить можно и нужно, колонку с ценами — не стоит: импорт из урока про [чтение ячеек](/courses/excelize/lessons/05-chtenie-yacheek/) сломается на ровном месте, а поиск причины затянется на вечер. Вертикальные слияния в данных мешают сильнее горизонтальных: колонка категорий, слитая на десять строк, в GetRows выглядит как одна заполненная и девять пустых, и группировка по ней соберёт мусор. Если файлы со слияниями приходят со стороны, первым делом постройте карту блоков через GetMergeCells — парсеру она нужнее самих строк, потому что отличает честные пустые ячейки от пустых внутри объединения.

### SetColWidth: ширина столбцов excelize в символах

Метод f.SetColWidth принимает лист, начальную и конечную колонку и ширину — один вызов покрывает диапазон: SetColWidth("Отчёт", "B", "D", 14) задаст ширину трём колонкам сразу, для одной начало и конец совпадают. Единица — не пиксель: ширина столбцов excelize измеряет в символах шрифта по умолчанию, точнее в ширине цифры ноль базового шрифта, поэтому 14 на Calibri и на другом шрифте занимают разное место. Предел — 255 символов, а колонка без явной ширины узкая, около 8.43. Значение пишется в файл и рисуется как есть: библиотека не измеряет содержимое, а в xlsx нет понятия «ширина текста» до открытия файла в Excel. Отсюда и отсутствие автоподбора из коробки: команда «автоширина» живёт в Excel и пересчитывает ширину по факту отображения. В генераторах автоподбор эмулируют: посчитать максимум длины строки в колонке и выставить SetColWidth с запасом — приём в коде ниже.

### Автоширина по содержимому

```go
rows, err := f.GetRows("Отчёт")
if err != nil {
    panic(err)
}

const cols = 4
for i := 0; i < cols; i++ {
    widest := 8.0
    for _, row := range rows {
        if i < len(row) {
            if l := float64(len([]rune(row[i]))); l > widest {
                widest = l
            }
        }
    }
    col, _ := excelize.ColumnNumberToName(i + 1)
    f.SetColWidth("Отчёт", col, col, widest*1.1+2)
}
```

Максимум длины строки в колонке считается в рунах: русские буквы занимают два байта в UTF-8, и подсчёт по байтам раздул бы колонку вдвое. Константа 8.0 держит нижнюю границу на уровне дефолта, множитель 1.1 и плюс два символа дают запас под шрифт. Считайте по отображаемым значениям: серийный номер даты короче строки 15.06.2024, которая видна на экране.

### Методы размеров одним взглядом

| Вызов | Что делает | Единицы |
| --- | --- | --- |
| f.MergeCell("Отчёт", "A1", "D1") | объединяет прямоугольник в один блок | ячейки |
| f.UnmergeCell("Отчёт", "A1", "D1") | снимает слияние по тем же координатам | ячейки |
| f.SetColWidth("Отчёт", "B", "D", 14) | ширина колонок диапазоном | символы шрифта |
| f.GetColWidth("Отчёт", "B") | текущая ширина колонки | символы шрифта |
| f.SetRowHeight("Отчёт", 1, 26) | высота строки | пункты |
| f.GetRowHeight("Отчёт", 2) | текущая высота строки | пункты |

### Высота строк и решётки вместо чисел

Высота задаётся SetRowHeight в пунктах: по умолчанию строка около 15 пунктов, шапке с тринадцатым шрифтом ставят 22–26, иначе верхушки букв упираются в границу. С переносом текста из урока про стили есть нюанс: Excel растит строку под переносимый текст сам, но только пока высота не задана вручную — после SetRowHeight автоподбор для этой строки отключается, и длинный текст обрезается. Числа ведут себя иначе текста: когда колонке не хватает ширины, Excel не обрезает значение и не лезет на соседей, а рисует решётки ##### — страдают деньги и даты первыми, у текста есть выход на пустую соседку. Датам формата DD.MM.YYYY из урока про [форматы чисел и дат](/courses/excelize/lessons/08-formaty-chisel/) нужно десять символов, а колонка по умолчанию — около 8.43: вот и решётки на первой же выгрузке. Лечение одно: ширину считает генератор по отображаемым значениям, а не надежда, что кто-то потянет границу колонки в Excel.

> **Карта слияний чужого файла.** GetMergeCells("Отчёт") возвращает список объединённых блоков, у каждого доступны координаты начала и конца. Скрипт, разбирающий чужие файлы, сначала строит карту блоков, потом читает строки: без неё объединённая шапка выглядит как строка с тремя пустыми ячейками и одним полным углом, и логика парсера от неё ломается.

### Чек-лист размеров

- MergeCell — прямоугольник в один блок: значение живёт в верхней-левой ячейке.
- Стиль блока прикладывайте на весь диапазон слияния, а не на угол.
- GetRows под слиянием видит пустые ячейки: данные держите без объединений.
- SetColWidth — ширина в символах шрифта: от и до, предел 255.
- SetRowHeight — высота в пунктах: шапке 22–26, данным по умолчанию.
- Решётки ##### — числу не хватило ширины: ширину считает генератор.

> **В песочнице файлов нет.** MergeCell и SetColWidth требуют книги на диске, поэтому в браузерной песочнице не запускаются: там доступны только fmt, strings, strconv, math, sort, errors и time без файлового ввода-вывода. Ядро автоширины в песочнице потренировать можно: посчитайте максимум длины строки в срезе срезов в рунах — логика та же, что в коде урока, а файл с шапкой соберите локально.

Кейс про решётки на фото экрана. Руководителю прислали квартальный отчёт, он открыл его и отправил назад скриншот: колонка дат вся в решётках, колонка денег — тоже. Причина считалась на пальцах: даты писались time.Time со стилем DD.MM.YYYY, отображаемая строка 15.06.2024 — десять символов, ширина колонки — дефолтные 8.43. Ширину посчитал генератор: максимум по отображаемым значениям каждой колонки, множитель 1.1 и два символа запаса; деньгам с рублём досталось 14, датам 12. Заголовок заодно объединили в один блок и подняли шапке высоту до 26. В команду ушло правило: файл открывается готовым, границу колонки в Excel никто не тянет. Ширины вынесли в константы рядом с описанием колонок отчёта: данные и их размеры живут в одном месте, и новая колонка добавляется одним блоком, а не правкой в двух концах файла. Спорная сторона: автоширина по максимуму раздувает колонку из-за одного выброса на двести строк; там, где выбросы ожидаемы, максимум отбрасывают и включают перенос текста — решение по данным, а не по вкусу.

### Проверка: где живёт значение блока

**Вопрос:** После f.MergeCell("Отчёт", "A1", "D1") где окажется значение ячейки A1?

- ✅ Останется в A1: верхняя-левая ячейка блока
- Растянется на все четыре ячейки A1:D1
- Переедет в D1: правая-нижняя ячейка
- Очистится: слияние стирает значения

Excel показывает значение верхней-левой ячейки по всей площади блока, но физически оно остаётся в A1, остальные ячейки пусты. Читайте и пишите блок через угловую координату.

### Проверка: ширина диапазоном

**Вопрос:** Какой вызов задаст ширину колонок B, C и D одной строкой?

- ✅ f.SetColWidth("Отчёт", "B", "D", 14)
- f.SetColWidth("Отчёт", "B", 14)
- f.SetColWidth("Отчёт", 2, 4, 14)
- f.SetRowWidth("Отчёт", "B", "D", 14)

SetColWidth принимает лист, начальную и конечную колонку буквами и ширину: B, D, 14 покрывает три колонки. Номера вместо букв — сигнатура древних версий из старых статей, а метода SetRowWidth в библиотеке нет.

### Что вернёт чтение из блока?

```go
f.SetCellValue("Sheet1", "A1", "Отчёт за квартал")

f.MergeCell("Sheet1", "A1", "D1")

val, _ := f.GetCellValue("Sheet1", "C1")

fmt.Println(val)
```

**Что выведет программа?**

- ✅ Пустую строку: значение только в верхней-левой ячейке
- Отчёт за квартал: значение видно через весь блок
- Ошибку: ячейка под слиянием недоступна
- Строку D1

MergeCell оставляет значение в верхней-левой ячейке, остальные ячейки блока пусты, и чтение по отдельной координате возвращает пустую строку. На экране Excel текст виден по всей площади, но GetCellValue живёт в мире данных, а не отображения.

### Соберите шапку по размеру

Допишите объединение блока, перевод номера колонки в букву, ширину и высоту.

```go
f.___("Отчёт", "A1", "D1")

col, _ := excelize.___(2)
f.___("Отчёт", col, col, 18)

f.___("Отчёт", 1, 26)
```

Подсказка: Объединяет MergeCell, номер колонки в букву переводит ColumnNumberToName, ширину ставит SetColWidth, высоту строки — SetRowHeight.

Правильные ответы в пропусках: `MergeCell`, `ColumnNumberToName`, `SetColWidth`, `SetRowHeight`

### Соберите шапку и её размеры

Расставьте строки в порядке выполнения: написать заголовок, объединить блок, создать стиль, проверить ошибку, применить стиль к блоку, задать ширину колонок.

Правильный порядок строк:

1. `f.SetCellValue("Отчёт", "A1", "Отчёт за второй квартал")`
2. `f.MergeCell("Отчёт", "A1", "D1")`
3. `header, err := f.NewStyle(&excelize.Style{Font: &excelize.Font{Bold: true}})`
4. `if err != nil { panic(err) }`
5. `f.SetCellStyle("Отчёт", "A1", "D1", header)`
6. `f.SetColWidth("Отчёт", "A", "D", 16)`

### Карточки: слияния и размеры

- **MergeCell** — Объединяет прямоугольник ячеек в блок: лист, верхняя-левая, нижняя-правая. Значение живёт в углу, остальные ячейки пусты.
- **UnmergeCell** — Снимает слияние по тем же координатам, что и MergeCell. Значение остаётся в верхней-левой ячейке блока.
- **GetMergeCells** — Список слияний листа с координатами начала и конца: карта блоков для парсера чужих файлов.
- **SetColWidth** — Ширина колонок от и до в символах шрифта: колонки буквами, предел 255, дефолт около 8.43.
- **SetRowHeight** — Высота строки в пунктах: дефолт около 15, шапке ставят 22–26. Ручная высота отключает автоподбор при переносе.
- **Решётки #####** — Числу или дате не хватило ширины колонки: Excel рисует решётки вместо обрезки. Лечится SetColWidth, текст в такой ситуации просто вылезает на соседей.

Геометрия закрыта: шапка стоит блоком, колонки не жмут данные, высота строк подогнана. Дальше файл станет умнее: в уроке про [формулы](/courses/excelize/lessons/11-formuly/) итоги посчитает сам Excel через SetCellFormula, а в уроке про [условное форматирование](/courses/excelize/lessons/12-uslovnoe-format/) колонка подсветит отрицательные остатки без единого нового стиля. Стили, границы и размеры из последних четырёх уроков складываются в готовый шаблон оформления — целиком он используется в [экспорте отчёта из базы](/courses/excelize/lessons/19-eksport-iz-bd/) и в разборе [типичных ошибок excelize](/courses/excelize/lessons/22-tipichnye-oshibki/). Если длина строки в рунах показалась тёмной темой, вернитесь к уроку про [строки и руны](/courses/go-basics/lessons/06-stroki-i-runes/) базового курса. Домашнее задание — шапка блоком и ширина по содержимому.

## Коротко: что запомнить

- MergeCell объединяет прямоугольник ячеек: значение остаётся в верхней-левой.
- Стиль слияния прикладывайте ко всему блоку, а не к углу.
- Чтение возвращает пустые строки для ячеек под слиянием: парсер должен знать карту блоков.
- SetColWidth задаёт ширину в символах шрифта: от и до, предел 255.
- SetRowHeight измеряет высоту в пунктах; ручная высота отключает автоподбор при переносе.
- Решётки ##### — числу не хватило ширины: ширину считает генератор по отображаемым значениям.

## Домашнее задание

В своём отчёте объедините шапку листа в один блок на все колонки данных и отцентрируйте её, поднимите высоту строки до 26, а колонкам посчитайте ширину по максимуму отображаемой длины с множителем 1.1 и двумя символами запаса. Проверьте GetMergeCells, что блок один, и убедитесь, что ни одна числовая колонка не показывает решётки.

## Вопросы и ответы по уроку

### Что вернёт GetCellValue для ячейки внутри слияния?

Пустую строку: значение хранится в верхней-левой ячейке блока, остальные Excel держит пустыми. На экране текст виден по всей площади, но чтение по отдельным ячейкам его не отдаёт — читайте угловую координату.

### Почему после MergeCell шапка покрашена наполовину?

Стиль применили только к угловой ячейке: заливка и границы лежат на каждой ячейке блока отдельно. Прикладывайте стиль SetCellStyle на тот же прямоугольник, что и слияние, — тогда оформление накроет весь блок.

### Есть ли в excelize автоподбор ширины, как в Excel?

Из коробки нет: в файле не хранится ширина содержимого, и библиотеке нечего измерять до открытия файла. Ширину считают при генерации — максимум длины отображаемых значений колонки, множитель 1.1 и пара символов запаса через SetColWidth.
