raw Software

Excel exposes two different measurements for a column. Range.ColumnWidth is writable, but its unit is based on the width of one character in the workbook's Normal style. With a proportional font, Excel uses the width of the digit zero. Range.Width, by contrast, is read-only and reports the rendered range width in points.

This mismatch matters when a workbook must reproduce a physical layout, align drawing objects with cells, or import dimensions specified in points, millimeters, centimeters, or inches. There is no direct writable ColumnWidthPoints property, so VBA has to set character units, measure points, and refine the result.

Why One Proportional Correction Is Not Exact

A tempting conversion scales the current character width by the ratio between target and measured points:

With Worksheets("Sheet1").Columns("A")
    .ColumnWidth = 123# / .Width * .ColumnWidth
End With

This often gets close, but it assumes that point width is exactly proportional to ColumnWidth. Excel applies font metrics, cell padding, and discrete width steps. The assigned character width is therefore rounded to a representable value, and the next .Width measurement may differ from the target. Repeating the expression a fixed number of times improves some cases without defining an error bound or a stopping condition.

The Normal style controls the character metric behind ColumnWidth. It can be inspected or changed under Home > Cell Styles > Normal > Modify:

Excel Normal cell style menu

A robust routine should not attempt to predict that font-dependent mapping. It should use .Width as the measured result and search the legal .ColumnWidth range.

Set a Single Column Width in Points

The function below performs a bounded binary search. It retains the best representable width seen, stops early when the requested tolerance is met, and returns the actual width in points. Excel's maximum ColumnWidth is 255 character units.

Option Explicit

Public Function SetColumnWidthPoints( _
    ByVal targetColumn As Range, _
    ByVal targetPoints As Double, _
    Optional ByVal tolerancePoints As Double = 0.25 _
) As Double
    Const MaxColumnWidth As Double = 255#
    Const MaxIterations As Long = 24

    If targetColumn Is Nothing Then
        Err.Raise 5, "SetColumnWidthPoints", "A target column is required."
    End If

    If targetColumn.Columns.Count <> 1 Then
        Err.Raise 5, "SetColumnWidthPoints", "Pass exactly one column."
    End If

    If targetPoints < 0# Then
        Err.Raise 5, "SetColumnWidthPoints", "The width cannot be negative."
    End If

    If tolerancePoints <= 0# Then
        Err.Raise 5, "SetColumnWidthPoints", "The tolerance must be positive."
    End If

    Dim columnRange As Range
    Set columnRange = targetColumn.Worksheet.Columns(targetColumn.Column)

    If targetPoints = 0# Then
        columnRange.Hidden = True
        SetColumnWidthPoints = 0#
        Exit Function
    End If

    Dim originalColumnWidth As Double
    Dim originalHidden As Boolean
    originalColumnWidth = columnRange.ColumnWidth
    originalHidden = columnRange.Hidden

    On Error GoTo RestoreOnError

    columnRange.Hidden = False
    columnRange.ColumnWidth = MaxColumnWidth

    If columnRange.Width + tolerancePoints < targetPoints Then
        Err.Raise vbObjectError + 2048, "SetColumnWidthPoints", _
            "The requested width exceeds Excel's maximum column width."
    End If

    Dim lowerBound As Double
    Dim upperBound As Double
    Dim candidate As Double
    Dim measuredPoints As Double
    Dim difference As Double
    Dim bestColumnWidth As Double
    Dim bestDifference As Double
    Dim iteration As Long

    lowerBound = 0#
    upperBound = MaxColumnWidth
    bestColumnWidth = columnRange.ColumnWidth
    bestDifference = Abs(columnRange.Width - targetPoints)

    For iteration = 1 To MaxIterations
        candidate = (lowerBound + upperBound) / 2#
        columnRange.ColumnWidth = candidate
        measuredPoints = columnRange.Width
        difference = Abs(measuredPoints - targetPoints)

        If difference < bestDifference Then
            bestDifference = difference
            bestColumnWidth = columnRange.ColumnWidth
        End If

        If difference <= tolerancePoints Then Exit For

        If measuredPoints < targetPoints Then
            lowerBound = candidate
        Else
            upperBound = candidate
        End If
    Next iteration

    columnRange.ColumnWidth = bestColumnWidth
    SetColumnWidthPoints = columnRange.Width
    Exit Function

RestoreOnError:
    Dim savedNumber As Long
    Dim savedSource As String
    Dim savedDescription As String

    savedNumber = Err.Number
    savedSource = Err.Source
    savedDescription = Err.Description

    On Error Resume Next
    columnRange.ColumnWidth = originalColumnWidth
    columnRange.Hidden = originalHidden
    On Error GoTo 0

    Err.Raise savedNumber, savedSource, savedDescription
End Function

Use the function with an entire column or any range that occupies exactly one column:

Dim actualPoints As Double

actualPoints = SetColumnWidthPoints( _
    Worksheets("Sheet1").Columns("A"), _
    123# _
)

Debug.Print "Actual width:"; actualPoints

The return value is important. Excel can represent only discrete widths, so an arbitrary target may not be exactly attainable. The default quarter-point tolerance is usually tighter than a visible layout requires, while the best measured candidate remains useful when the loop reaches its iteration limit.

Convert Inches, Centimeters, and Millimeters

Excel provides conversion methods for inches and centimeters. Convert millimeters to centimeters first:

Dim widthInInches As Double
Dim widthInCentimeters As Double
Dim widthInMillimeters As Double

widthInInches = Application.InchesToPoints(1.75)
widthInCentimeters = Application.CentimetersToPoints(4.5)
widthInMillimeters = Application.CentimetersToPoints(45# / 10#)

Call SetColumnWidthPoints(Columns("B"), widthInInches)
Call SetColumnWidthPoints(Columns("C"), widthInCentimeters)
Call SetColumnWidthPoints(Columns("D"), widthInMillimeters)

A point is exactly 1/72 inch. The built-in methods are preferable to repeating conversion constants throughout a workbook and make the unit at each call site explicit.

Apply a Width to Several Columns

The function deliberately accepts one column because ColumnWidth returns Null when a multi-column range contains different widths. Loop explicitly when several columns need the same physical width:

Dim oneColumn As Range
Dim targetPoints As Double

targetPoints = Application.CentimetersToPoints(3#)

For Each oneColumn In Worksheets("Sheet1").Columns("B:D").Columns
    Call SetColumnWidthPoints(oneColumn, targetPoints)
Next oneColumn

This also makes partial failure visible: each iteration targets one unambiguous Excel column.

Understand the Limits

If the goal is simply to reveal all cell contents, use Columns("A").AutoFit. Point-based sizing is for layouts where physical dimensions matter more than the current cell contents.

References